Объединение двух связанных списков без дублирования

0

Я хочу написать код для слияния двух связанных списков, чтобы в результирующем списке не было дублирования. Эти два списка упорядочены, но могут иметь дублирование внутри них. Полученный список должен быть сохранен в текущем списке. Код должен работать в 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);
}

Любая недостающая информация?

  • 1
    Почему бы не использовать set_union? cplusplus.com/reference/algorithm/set_union
  • 0
    Это алгоритм слияния из сортировки слиянием. Однако он основан на предположении, что списки не содержат дубликатов, поэтому он не будет работать здесь. Рассмотрим два списка: 1 1 и 2 2 . Этот код добавит оба 1 с подряд, потому что они оба меньше 2 .
Показать ещё 2 комментария
Теги:
list
algorithm
merge

2 ответа

2
Лучший ответ

Следующее будет работать, так как списки находятся в порядке убывания, и новый список также создается в порядке убывания.

Перед добавлением следующего элемента в новый список просто добавьте проверку:

if ( newNodeValue < lastAddedNodeValue )
  //only then add to list.
  • 0
    Удивительно. Это работает, но есть проблема, когда мы добавляем первый элемент в newList, тогда мы не можем проверить последнее добавленное значение, потому что хвост будет NULL.
  • 0
    Другое дело, что условие if должно быть (newNodeValue> lastAddedNodeValue), потому что newList должен сортироваться по убыванию.
Показать ещё 3 комментария
3

Замените каждое приращение итератора вызовом:

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->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);
}   
  • 0
    @ammarx: отредактировано.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню