0

(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 D.S. 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!

1 Answer 1

0

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, e.g. addToFront().

Hope that helps!

Sign up to request clarification or add additional context in comments.

2 Comments

Yes, those suggested additions did it! Thanks so much!! But, where is the problem with addToFront?
Happy to hear that the suggestions helped. Please accept the answer if you consider it the best one. As a hint to the issue with addToFront, in your driver program, as the first action, add an entry to the front of an empty list. Once that works properly, with a list containing one entry, pop from front and you will be able to fix another bug.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.