0

I am trying to create a function for adding at the end for doubly linklist. I can't pinpoint out why it does not print out anything.

There was no error coming out when I build the program.

I am making sure 1. new node check if the head has any value first

  1. created following pointer that is previous current

  2. I connected previous node to new node and new node point to previous node while new node point out to nullptr as next.

#include "pch.h"
#include <iostream>

using namespace std;

class list;

class node {
public:
    int data;
    node *next;
    node *prev;
    friend class list;
};


class list {//double list 
    node* head;
    node* tail;
public:
    list(){ head = nullptr; tail = nullptr; head->next = tail; tail->prev = head;}
    node* pushback(int newdata) {
        node* curr = new node;
        curr->data = newdata;
        curr->next = nullptr;
        if (head == nullptr) {
            head = curr;
            return head;
        }
        node*precurr = head;
        while (precurr->next != nullptr){
            precurr = precurr->next;
        }
        precurr->next = curr;
        curr->prev = precurr;
        return head;
    }
    void print() {
        while (head->next != nullptr) {
            cout << head->data << " " << endl;
            head = head->next;
        }
    }
};

int main()
{
    list test;

    test.pushback(1);
    test.pushback(2);
    test.pushback(3);
    test.pushback(4);
    test.pushback(5);
    test.pushback(6);

    test.print();

    return 0;
}
George Go
  • 73
  • 1
  • 9
  • You `list` constructor has UB. You are setting `head` to `nullptr`, and then immediately using `head->next`. – cigien May 11 '20 at 01:19
  • When I run your code, I get a segmentation fault (which would be a more concerning symptom than not printing the contents of your list). When I fix the segmentation fault (UB), the code works. It's not great since it ignores `tail`, but it does print out the list. – JaMiT May 11 '20 at 01:56

1 Answers1

1

You have done a lot of things correctly, but you are confused on your constructor and on your use of the ->prev and tail pointers.

You immediate issue with your constructor, as identified in the comments, is you set head and tail to nullptr and then immediately derefernce both head and tail attempting to make head and tail self-referencing (which is only needed in a circular linked-list).

list(){ head = nullptr; tail = nullptr; head->next = tail; tail->prev = head;}

With head and tail to set to nullptr, you don't have a pointer to a valid node than can be dereferenced. Your attempt to set head->next = tail; tail->prev = head; fails immediately resulting in a SegFault.

For purposes on a normal non-circular list, you simply omit setting head->next and tail->prev in your constructor, e.g.

    list() { head = nullptr; tail = nullptr; }

If you want to make your list a circular list, then you will make head and tail self-referencing in:

    node *pushback (int newdata) {
        ...
        if (head == nullptr)     /* for circular-list 1st node initialization */
            head = tail = head->prev = head->next = tail->prev = tail->next = curr;

(note: a tail pointer is optional with a circular list as head->prev always points to the last node in the list)

Since your question pertains to a double-linked-list and not a circular list, you simply need to set both head and tail equal to the new node curr for the addition of the 1st node, e.g.

    node *pushback (int newdata) {
        node *curr = new node;
        curr->data = newdata;
        curr->next = curr->prev = nullptr;

        if (head == nullptr)
            head = tail = curr;

For all other nodes, there is NO iteration required (that's what a tail pointer is for), you simply set curr->prev to tail, tail->next to curr and then update the tail pointer to the new end node by setting tail = curr;, e.g.

        else {
            curr->prev = tail;
            tail->next = curr;
            tail = curr;
        }

        return head;
    }

The purpose of a double-linked-list is to allow you to iterate in both the forward and reverse direction over your nodes. For example:

    void printfwd() {
        node *iter = head;
        while (iter != nullptr) {
            std::cout << ' ' << iter->data;
            iter = iter->next;
        }
        std::cout.put('\n');
    }
    void printrev() {
        node *iter = tail;
        while (iter != nullptr) {
            std::cout << ' ' << iter->data;
            iter = iter->prev;
        }
        std::cout.put('\n');
    }

(the iteration scheme is slightly different for a circular list since you can iterate from any node in both forward and reverse direction without needed to start from head or tail. To insert in order for a circular list, you simply insert a new tail node).

Don't develop bad habits. Why is “using namespace std;” considered bad practice? Currently all you have to deal with is cout and endl, go ahead and remove using namespace std; and simply prefix cout and endl with std::.

Putting it altogether, you would have:

#include <iostream>

class list;

class node {
public:
    int data;
    node *next;
    node *prev;
    friend class list;
};

class list {//double list 
    node *head;
    node *tail;
public:
    list() { head = nullptr; tail = nullptr; }
    node *pushback (int newdata) {
        node *curr = new node;
        curr->data = newdata;
        curr->next = curr->prev = nullptr;

        if (head == nullptr)
            head = tail = curr;
        else {
            curr->prev = tail;
            tail->next = curr;
            tail = curr;
        }

        return head;
    }
    void printfwd() {
        node *iter = head;
        while (iter != nullptr) {
            std::cout << ' ' << iter->data;
            iter = iter->next;
        }
        std::cout.put('\n');
    }
    void printrev() {
        node *iter = tail;
        while (iter != nullptr) {
            std::cout << ' ' << iter->data;
            iter = iter->prev;
        }
        std::cout.put('\n');
    }
};

int main() {

    list test;

    for (int i = 1; i <= 10; i++)
        test.pushback(i);

    std::cout << "\nforward:\n";
    test.printfwd();
    std::cout << "\nreverse:\n";
    test.printrev();
}

Example Use/Output

$ ./bin/ll_double_int

forward:
 1 2 3 4 5 6 7 8 9 10

reverse:
 10 9 8 7 6 5 4 3 2 1

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85