简体   繁体   中英

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

(FYI, first ever post to StackOverflow)

I am trying to implement a merge sort for doubly-linked lists in C++. While the sort does work, it's not rebuilding the list properly. It seems to be coming out as a singly-linked list with no "previous" pointers; the list can be read forward, but when I try to display it backwards, only the last node is shown. I think something must be wrong with the "merge" routine but I can't find where it is.

To start, here is the code for the doubly-linked node of which the list is made:

#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;
}

Here is the doubly-linked list class, stripped down to only those functions needed to build up a list and sort it: (FYI, this follows the algorithm presented in "C++ Programming: Program Design Including Data Structures", 6th ed. by DS Malik)

#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;
    }
}

Here is a driver program to test it:

#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;
}

If you can run this, you'll see that the sorted list is shown properly by displayForwards, but not shown in reverse by displayBackwards.

I hope I've provided enough information for help! I guess something must be wrong with the part of the merge step where the backwards link is made, I just don't see it!

cheers, and thanks in advance!

The main issue in the merge step occurs in the case when one sublist is exhausted first. The remainder of the other list is appended to the end of the merge list but none of the prev pointers are being maintained. At the bottom of mergeList(), it should look like this:

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

Also, there asymmetry in the main while loop that seems like a mistake

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

Lastly, there are a few places where an single element list isn't being handled properly, eg addToFront().

Hope that helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM