在C++中实现双链表合并排序时出现问题

Trouble implementing merge sort on doubly-linked list in C++

本文关键字:排序 问题 合并 链表 C++ 实现      更新时间:2023-10-16

(仅供参考,首次发布到StackOverflow)

我正在尝试在C++中实现双链表的合并排序。虽然排序确实有效,但它没有正确地重建列表。它似乎是一个没有"以前"指针的单链列表;列表可以向前读取,但当我尝试向后显示时,只显示最后一个节点。我认为"合并"程序一定有问题,但我找不到它在哪里。

首先,这里是列表中的双链接节点的代码:

#include <iostream>
using namespace std;
class DLNode
{
public:
    int data;
    DLNode* prev;
    DLNode* next;
    DLNode();
    DLNode(int entry);
};
DLNode::DLNode()
{
    data = -99999;
    prev = NULL;
    next = NULL;
}
DLNode::DLNode(int entry)
{
    data = entry;
    prev = NULL;
    next = NULL;
}

这是一个双链接列表类,它被简化为只需要建立列表并对其排序的函数:(仅供参考,这遵循D.S.Malik第6版《C++编程:包括数据结构的程序设计》中提出的算法)

#include "DLNode.h"  //the doubly-linked node class above
using namespace std;
class DblLinkList
{
private:
    DLNode* head;  //pointer to head of list
    DLNode* last;  //pointer to end of list
    int count;  //keeps count of number of items in list
    //these 3 methods are used only to implement a mergeSort, called within sort() function
    void splitList(DLNode* first1, DLNode*& first2);
    DLNode* mergeList(DLNode* first1, DLNode* first2);
    void recMergeSort(DLNode* &head);
public:
    DblLinkList();
    void displayForwards();
    void displayBackwards();
    int getCount();
    void addToFront(int entry);
    void addToBack(int entry);
    int popFront();
    int popBack();
    void sort();        
};
DblLinkList::DblLinkList()
{
    head = NULL;
    last = NULL;
    count = 0;
}
void DblLinkList::addToFront(int entry)
{
    DLNode* tmpDLNode = new DLNode();
    tmpDLNode->data = entry;  
    head->prev = tmpDLNode;
    tmpDLNode->next = head;  
    head = tmpDLNode;  
    head->prev = NULL;
    count++;
    if (last==NULL)
        last=tmpDLNode;
    //cout << head->data << endl;
    //cout << last->data << endl;
}
void DblLinkList::addToBack(int entry)
{
    DLNode* tmpDLNode = new DLNode();
    tmpDLNode->data = entry;  
    tmpDLNode->next = NULL;  
    tmpDLNode->prev = NULL;  
    if (head==NULL)  //if list is empty
    {
        head=tmpDLNode;
        last=tmpDLNode;
    }
    else  //if list is not empty
    {
        tmpDLNode->prev = last;
        last->next = tmpDLNode;
        last = tmpDLNode;
        last->next = NULL;
        //cout << head->data << endl;
        //cout << last->data << endl;
    }
    count++;
}
int DblLinkList::popFront()
{
    DLNode* trash;
    int popval;
   if (head==NULL)
       cout << "List empty, nothing to pop." << endl;
   else
   {
       trash = head;
       popval = head->data;
       head = head->next;
       head->prev = NULL;
       count--;
       delete trash;
   }
   return popval;
}
int DblLinkList::popBack()
{
    DLNode* trash;
    int popval;
   if (head==NULL)
       cout << "List empty, nothing to pop." << endl;
   else if (head==last) 
       popFront();
   else
   {
       trash = last;
       popval = last->data;
       last = last->prev;
       last->next = NULL;
       count--;
       delete trash;
   }
   return popval;
}

void DblLinkList::displayForwards()
{
    DLNode* yad;
    yad = head;
    while (yad != NULL)
    {
        cout << yad->data << " ";
        yad = yad->next;
    }
    cout << endl;
}
void DblLinkList::displayBackwards()
{
    DLNode* yad;
    yad = last;
    while (yad != NULL)
    {
        cout << yad->data << " ";
        yad = yad->prev;
    }
    cout << endl;
}
int DblLinkList::getCount()
{
    return count;
}
//private function used only to implement sort()
void DblLinkList::splitList(DLNode* first1, DLNode* &first2)  
{
    DLNode* middle;
    DLNode* current;
    if(first1==NULL)
        first2 = NULL;
    else if (first1->next == NULL)
        first2 = NULL;
    else
    {
        middle = first1;
        current = first1->next;
        if (current != NULL)
            current = current->next;
        while (current != NULL)
        {
            middle = middle->next;
            current = current->next;
            if (current != NULL)
                current = current->next;
        }
        first2 = middle->next;
        middle->next = NULL;
        first2->prev = NULL;
    }
}
DLNode* DblLinkList::mergeList(DLNode* first1, DLNode* first2)
{
    DLNode* lastSmall;
    DLNode* newHead;
    if (first1==NULL)
        return first2;
    else if (first2==NULL)
        return first1;
    else
    {   //first figure out which list's head should be the head of the merged list
        if (first1->data < first2->data)
        {
            newHead = first1;
            first1 = first1->next;
            lastSmall = newHead;
        }
        else
        {
            newHead = first2;
            first2 = first2->next;
            lastSmall = newHead;
        }
        while ((first1 != NULL) && (first2 != NULL))
        {
            if (first1->data < first2->data)
            {
                lastSmall->next = first1;
                lastSmall = lastSmall->next;
                first1 = first1->next;
            }
            else
            {
                first2->prev = lastSmall;
                lastSmall->next = first2;
                lastSmall = lastSmall->next;
                first2 = first2->next;
            }
        }
        if (first1 == NULL)
            lastSmall->next = first2;
        else
            lastSmall->next = first1;
        return newHead;
    }
}
void DblLinkList::recMergeSort(DLNode* &head)
{
    DLNode* otherHead;
    if (head != NULL)
        if (head->next != NULL)
        {
            splitList(head, otherHead);
            recMergeSort(head);
            recMergeSort(otherHead);
            head = mergeList(head,otherHead);
        }
}
//public sort function
void DblLinkList::sort()
{
    recMergeSort(head);
    if (head == NULL)
        last = NULL;
    else
    {
        last = head;
        while (last->next != NULL)
            last = last->next;
    }
}

下面是一个测试它的驱动程序:

#include <iostream>
#include "DblLinkList.h" //the doubly-linked list class above
using namespace std;
int main()
{
    DblLinkList myDLList;
    myDLList.addToBack(10);
    myDLList.addToBack(40);
    myDLList.addToBack(30);
    myDLList.addToBack(20);
    myDLList.addToBack(50);
    myDLList.addToBack(70);
    myDLList.addToBack(80);
    myDLList.addToBack(60);
    myDLList.addToBack(90);
    myDLList.addToBack(100);
    myDLList.displayForwards();
    myDLList.displayBackwards();
    myDLList.sort();
    myDLList.displayForwards();
    myDLList.displayBackwards();
    cout << myDLList.getCount() << endl;
    system("pause");
    return 0;
}

如果你能运行这个,你会看到排序列表通过displayForwards正确显示,但通过displayBackwards没有反向显示。

我希望我已经提供了足够的帮助信息!我想合并步骤中向后链接的部分一定出了问题,我就是没看到!

干杯,提前感谢!

合并步骤中的主要问题发生在首先耗尽一个子列表的情况下。其他列表的其余部分被附加到合并列表的末尾,但没有保留任何prev指针。在mergeList()的底部,它应该是这样的:

    if (first1 == NULL) {
        lastSmall->next = first2;
        first2->prev = lastSmall; <------
    }
    else {
        lastSmall->next = first1;
        first1->prev = lastSmall; <------
    }
    return newHead;

此外,主while循环中存在不对称,这似乎是的错误

    while ((first1 != NULL) && (first2 != NULL))
    {
        if (first1->data < first2->data)
        {
            first1->prev = lastSmall; <------ missing?
            lastSmall->next = first1;
            lastSmall = lastSmall->next;
            first1 = first1->next;
        }
        else

最后,有一些地方没有正确处理单个元素列表,例如addToFront()。

希望能有所帮助!