Warerre
Warerre

Reputation: 1

How to print a Doubly Linked list?

I can't figure out why my print functions won't work. It seems that when i create objects of the list they do not point at each other as expected. Somehow when those objects are created they will point to nullptr in both directions.


#include <iostream>
#include <string>
#include <stdexcept>

template <typename T> 
class doubly_list {
private: 
    doubly_list* next_node;
    doubly_list* prev_node;
    T value = T();
public : 
    doubly_list(const T& nvalue, doubly_list* next = nullptr, doubly_list* prev = nullptr)
        : value(nvalue), next_node(next), prev_node(prev) {
    }

    doubly_list* getnext_node() const { return next_node; }
    doubly_list* getprev_node() const { return prev_node; }
    T getlist_value() const { return value; }
    
    doubly_list* move_to_the_next_node() const { return next_node; }
    doubly_list* move_to_the_prev_node() const { return prev_node; }

    doubly_list* insert(doubly_list* next);                       // adding next before prev 
    doubly_list* insert(doubly_list* prev, doubly_list* next);    // adding next before prev 

    void print_the_list(doubly_list<T>* head) const;              //print the list
};

//adding next before prev 
template<typename T>
doubly_list<T>* doubly_list<T>::insert(doubly_list* next) {
    if (this == nullptr) return next; 
    if (next == nullptr) return nullptr;

    next->next_node = this;

    if (this->prev_node) this->prev_node->next_node = next;

    this->prev_node = next->prev_node;
    this->prev_node = next;

    return next;
}
//next before prev
template<typename T>
doubly_list<T>* doubly_list<T>::insert(doubly_list* prev ,doubly_list* next) {
    if (prev == nullptr) return next; 
    if (next == nullptr) return nullptr;

    doubly_list<T>* current_node = next;

    current_node->next_node = prev;
    prev->prev_node = current_node;

    current_node->prev_node = nullptr;


    if (prev->prev_node != nullptr) {
        prev->prev_node->next_node = current_node;

        prev->prev_node = next->prev_node;
    }
        
    return next;
}
//printing the list 
template<typename T> 
void doubly_list<T>::print_the_list(doubly_list<T>* head) const {
    //checking if the list is valid
    if (!head) throw std::invalid_argument("No members found in the list");
    //actual output
    if (head->next_node == nullptr) {
        std::cout << "{" << std::endl;
        while (head) {
            std::cout << head->value;
            head = head->prev_node;
        }
        std::cout << "}" << std::endl; 
    }
    else if (head->prev_node == nullptr) {
        std::cout << "{"; 
        while (head) {
            std::cout << head->value;
            head = head->next_node;
        }
        std::cout << "}" << std::endl; 
    }
}
int main () { 

     auto head = new doubly_list<std::string>("1");
     head->insert(head ,new doubly_list<std::string>("2"));
     head->insert(head ,new doubly_list<std::string>("3"));
     head->insert(head ,new doubly_list<std::string>("4"));

     head->print_the_list(head);
        
     return 0;

}

I am learning c++ with Bjarne Stroustrup's Principles and Practice book and i wanted to implement this using templates but i was following book's guidence .

I thought that it must be some kind of a logical problem , so i've written those functions couple of times but it was pointless .

Upvotes: 0

Views: 59

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597941

After your insert() calls, none of the nodes are pointing where they should be.

The head's prev_node and next_node members are both nullptr, which is why your print doesn't work.

And in every other node, its prev_node member is still nullptr, and its next_node member is pointing at itself.

In this Demo, I added code to print out each node's members, and this is what I see:

0x557eba303eb0 value=1 prev=0 next=0
0x557eba303ef0 value=2 prev=0 next=0x557eba303ef0
0x557eba303f30 value=3 prev=0 next=0x557eba303f30
0x557eba303f70 value=4 prev=0 next=0x557eba303f70

It should have looked like this instead:

0x557eba303eb0 value=1 prev=0 next=0x557eba303ef0
0x557eba303ef0 value=2 prev=0x557eba303eb0 next=0x557eba303f30
0x557eba303f30 value=3 prev=0x557eba303ef0 next=0x557eba303f70
0x557eba303f70 value=4 prev=0x557eba303f30 next=0

So, you need to review your insert logic in a debugger and fix it, as it is quite broken.

Had you called your 1-param insert() instead of your 2-param insert(), then you can get a viable list - albeit in reverse order since that is the way you implemented its logic:

auto head = new doubly_list<std::string>("1");
head = head->insert(new doubly_list<std::string>("2"));
head = head->insert(new doubly_list<std::string>("3"));
head = head->insert(new doubly_list<std::string>("4"));

head->print_the_list(head); // prints: {4321}

Demo

That being said, in general this is not the best way to design a linked list. Nodes should not manage each other. Create a separate LinkedList class which holds a head (and preferably tail) member, and implement your insert() and print() methods on that class instead.

Upvotes: 1

Related Questions