Search code examples
c++linked-listbubble-sort

Bubble sort a doubly linked list


I've gone through a bunch of threads trying to understand what is going on exactly with linked lists and bubblesort, and I think I get the bulk of it.

Right now my program is simply crashing when I get to the sort function and I am not sure why. Hopefully another set of eyes will see what I do not.

Any help is greatly appreciated.

DoublyList.h:

#include "listNode.h"

#ifndef DOUBLYLIST_H
#define DOUBLYLIST_H

template <typename T>
class DoublyList
{
    public:
        DoublyList();
        ~DoublyList();
        void addFront(T d);
        void addBack(T d);
        T removeFront();
        T removeBack();
        T peak();
        bool isEmpty();
        int getSize();
        void printList();
        void sortList();

    private:
        ListNode<T> *front;
        ListNode<T> *back;
        int numOfElements;
};

template <typename T>
DoublyList<T>::DoublyList(){
    front = NULL;
    back = NULL;
    numOfElements = 0;
}
template <typename T>
DoublyList<T>::~DoublyList(){
    if(numOfElements!=0){

        ListNode<T> *current;
        current = front;
        while (current != back)
        {
            ListNode<T> *temp = current;
            current = current->next;
            temp->next = NULL;
            temp->prev = NULL;
            delete temp;
            numOfElements--;
        }
        //at this point current = back, now delete it
        current->next = NULL;
        current->prev = NULL;
        delete current;
        numOfElements--;
    }
    //this is a safeguard if you create a LL and then delete it without doing anything to it
    else{
        cout<<"deleted empty LL"<<endl;
        delete front;
        delete back;
    }
}
template <typename T>
void DoublyList<T>::addFront(T d)
{
    ListNode<T> *node = new ListNode<T>();
    node->data = d;
    if (isEmpty()){
        back = node;
    }
    else{
        front->prev = node;
    }
    node->next = front;
    front = node;
    ++numOfElements;
}
template <typename T>
T DoublyList<T>::removeFront()
{
    if (isEmpty()){
        return T();
    }
    else
    {
        ListNode<T>* temp = front;
        if (front->next == 0){
            back = 0;
        }
        else
        {
            front->next->prev = 0;
        }
        front = front->next;
        temp->next = 0;
        T theData = temp->data;
        delete temp;
        --numOfElements;
        return theData;
    }
}
template <typename T>
void DoublyList<T>::addBack(T d)
{
    ListNode<T> *node = new ListNode<T>();
    node->data = d;
    if (isEmpty()){
        front = node;
    }
    else{
        back->next = node;
    }
    node->prev = back;
    back = node;
    ++numOfElements;
}
template <typename T>
T DoublyList<T>::removeBack()
{
    if (isEmpty()) {
        return T();
    }
    else
    {
        ListNode<T>* temp;
        temp = back;
        if (back->prev == 0){
            front = 0;
        }
        else{
            back->prev->next = 0;
        }
        back = back->prev;
        temp->prev = 0;    
        T theData = temp->data;
        delete temp;
        --numOfElements;
        return theData;
    }
}
template <typename T>
T DoublyList<T>::peak()
{
    if (isEmpty()) {
        return T();
    }
    return front->data;
}
template <typename T>
int DoublyList<T>::getSize(){
    return numOfElements;
}
template <typename T>
bool DoublyList<T>::isEmpty(){
    if(numOfElements == 0){
        return true;
    }
    else{
        return false;
    }
}
template <typename T>
void DoublyList<T>::printList(){
    if(numOfElements!=0){
        ListNode<T> *current = front;
        while(current!=back)
        {
            cout<<current->data<<endl;
            current = current->next;
        }
        cout<<back->data<<endl;
    }
    else{
        cout<<"list is empty"<<endl;
    }
}


template <typename T>
void DoublyList<T>::sortList(){
    int size = getSize();
    ListNode<T> *current;
    ListNode<T> *dummy;
    ListNode<T> *next;

    if(current == NULL) return;
    if(current -> next == NULL) return;

    int swapped = 1;
    while(swapped){
        swapped = 0; //last pass unless there is a swap
        while(current -> next != NULL){
            if(current-> data < current -> next -> data){
                swapped = 1; //swap, will need to re-enter while loop
                //actual number swap
                dummy -> data = current -> data;
                current -> data = current -> next -> data;
                current -> next -> data = dummy -> data;
            }
            current = current -> next;
        }
    }

}

#endif

listNode.h:

#include <iostream>
#ifndef LISTNODE_H
#define LISTNODE_H

using namespace std;
template <typename T>
class ListNode
{
    public:
        T data;//the data that we will store
        ListNode();
        ListNode(int d);
        ~ListNode();
        ListNode *next;//int and ptr and the member variables
        ListNode *prev;
};
template <typename T>
ListNode<T>::ListNode(int d){
    data = d;
    next = NULL;
    prev = NULL;
}
template <typename T>
ListNode<T>::ListNode(){}
template <typename T>
ListNode<T>::~ListNode(){
    delete next;
    delete prev;
    cout<<"deleted Node"<<endl;
}
#endif

testList.cpp

#include <iostream>
#include "doublyList.h"
#include "genericQueue.h"




int main(){
    DoublyList<int> testQueue;
    testQueue.addBack(3);
    testQueue.addBack(5);
    testQueue.addBack(2);
    testQueue.addBack(10);
    testQueue.addBack(1);

    cout << "Before Sort: " << endl;
    testQueue.printList();

    cout << "After Sort: " << endl;
    testQueue.sortList();
    testQueue.printList();

}

Solution

  • The erors I could find so far are:

    1. Your default ListNode() constructor doesn't null the next and prev pointers.
    2. In void DoublyList<T>::sortList() you don't initialize dummy, so it just points into nowhere. Actually there is no reason to use a node list at all, you can just directly use a variable of type T.
    3. You don't initialize current in the same function and you actually should reset current to e.g. front at the beginning of each outer loop.
    4. You don't use next at all (and don't need to), so just remove it.

    To sum it up, this is what void DoublyList<T>::sortList() could look like:

    template <typename T>
    void DoublyList<T>::sortList(){
        int size = getSize();
        ListNode<T> *current=front;
        T dummy;
    
        if (current == NULL) return;
        if (current->next == NULL) return;
    
        int swapped = 1;
        while (swapped){
            current = front;
            swapped = 0; //last pass unless there is a swap
            while (current->next != NULL){
                if (current->data < current->next->data){
                    swapped = 1; //swap, will need to re-enter while loop
                    //actual number swap
                    dummy = current->data;
                    current->data = current->next->data;
                    current->next->data = dummy;
                }
                current = current->next;
            }
        }
    }
    

    and this is my suggestion for the ListNode constructor.

    template <typename T>
    ListNode<T>::ListNode() :
        next(nullptr), 
        prev(nullptr), 
        data{}
    {}
    

    Besides that, I also agree with DaveB that swapping pointers is the approach you should actually use.