【问题标题】:Merging two linked lists with no duplication合并两个不重复的链表
【发布时间】:2014-01-15 04:52:29
【问题描述】:

我想编写一个代码来合并两个链表,以使结果列表没有重复。这两个列表是有序的,但其中可能有重复。结果列表应存储在当前列表中。代码应该在O(n1+n2) 时间运行,其中 n1 是当前列表的大小,n2 是另一个列表的大小。

这是一个合并两个列表但重复的代码。这段代码的运行时间是O(n1+n2),它将结果列表存储到当前列表中:

template <class T>
void DLList<T>::MergeInOrder(DLList<T>& otherList)
{
    if(otherList.IsEmpty() == true)
        return;
    if(IsEmpty() == true)
    {
        Append(otherList);
        return;
    }

    DLList<T> newList; 
    DLLNode<T> *thisPtr, *otherPtr;

    for(thisPtr = this->head, otherPtr = otherList.head;
        thisPtr != NULL || otherPtr != NULL; )
    {
        if(otherPtr == NULL)
        {
            newList.AddToTail(thisPtr->val);
            thisPtr = thisPtr->next;
        } 
        else if(thisPtr == NULL)
        {
            newList.AddToTail(otherPtr->val);
            otherPtr = otherPtr->next;
        }   
        else if(thisPtr->val <= otherPtr->val)
        {
            newList.AddToTail(thisPtr->val);
            thisPtr = thisPtr->next;
        }
        else
        {
            newList.AddToTail(otherPtr->val);
            otherPtr = otherPtr->next;
        }
    }
    Clear();
    Append(newList);
}

有什么遗漏的信息吗?

【问题讨论】:

  • 为什么不使用 set_union? cplusplus.com/reference/algorithm/set_union
  • 这是归并排序的归并算法。然而,它依赖于列表不包含重复项的假设,因此它在这里不起作用。考虑两个列表:1 1 和 2 2。此代码将连续添加两个1s,因为它们都小于2。
  • 您对列表中的元素,特别是它们的顺序有任何保证吗?也就是说,如果 x 在 L1 中出现在 y 之后,那么 x' 在 L2 中出现在 y' 之后?
  • 这两个列表必须按降序排列。上面的代码可以正常工作,但不考虑重复。

标签: c++ algorithm list merge


【解决方案1】:

通过调用来替换每个迭代器的增量:

DLLNode<T>* nextDifferent(DLLNode<T> &node)
{
    const T& val = node.val;
    DLLNode<T> *res = node.next;

    while (res != nullptr && res->val == val) {
        res = res->next;
    }
    return res;
}

所以thisPtr = thisPtr-&gt;next; 变成了thisPtr = nextDifferent(*thisPtr);。

编辑

你的循环应该是这样的:

for (thisPtr = this->head, otherPtr = otherList.head;
    thisPtr != NULL && otherPtr != NULL; )
{
    if (thisPtr->val < otherPtr->val)
    {
        newList.AddToTail(thisPtr->val);
        thisPtr = nextDifferent(*thisPtr);
    }
    else if (otherPtr->val < thisPtr->val)
    {
        newList.AddToTail(otherPtr->val);
        otherPtr = nextDifferent(*otherPtr);
    } else { // they are equal
        newList.AddToTail(otherPtr->val);
        otherPtr = nextDifferent(*otherPtr);
        thisPtr = nextDifferent(*thisPtr);
    }
}

while (otherPtr != NULL)
{
    newList.AddToTail(otherPtr->val);
    otherPtr = nextDifferent(*otherPtr);
}
while (thisPtr == NULL)
{
    newList.AddToTail(thisPtr->val);
    thisPtr = nextDifferent(*thisPtr);
}   

【讨论】:

    【解决方案2】:

    以下将起作用,因为列表按降序排列,并且新列表也在按降序构建。

    在将下一个元素添加到新列表之前,只需添加一个检查:

    if ( newNodeValue < lastAddedNodeValue )
      //only then add to list.
    

    【讨论】:

    • 太棒了。这可行,但有一个问题是,当我们将第一个元素添加到 newList 时,我们无法检查最后添加的值,因为尾部将为 NULL。
    • 另外一个 if 的条件应该是 (newNodeValue > lastAddedNodeValue) 因为 newList 应该降序排序。
    • @ammarx 用于降序列表新的 noee 值应该小于最后一个节点值。您可以通过正确初始化 lastnodevalue 轻松修复您的第一点
    • 对不起,你是对的。该列表应按升序排列,条件应为 (newNodeValue > lastAddedNodeValue)。当我不知道 list1 和 list2 元素的范围时,我无法初始化 newList!。
    • 所以条件应该是if (newList.Empty() || newNodeValue != lastAddedNode-&gt;val)。
    猜你喜欢
    • 2021-12-29
    • 2013-09-08
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    相关资源
    最近更新 更多