Inserting into a Doubly Linked List - c++

I am trying to create a doubly linked list container for a project. I cannot use any std containers. The doubly linked list has to be sorted. Here is my code so far:
#include <iostream>
using namespace std;
template <typename T>
class dll {
private:
struct Node {
Node* prev;
Node* next;
T data;
};
Node* head;
Node* tail;
public:
dll();
~dll();
void insert(T value);
bool empty() const { return head == tail; };
};
template <typename T> dll<T>::dll() {
head = nullptr;
tail = head;
}
template <typename T> dll<T>::~dll() {
delete[] head;
}
template <typename T> void dll<T>::insert(T value) {
Node *node = new Node;
node->data = value;
// Case 1: There are no nodes yet
if (head == nullptr) {
node->prev = nullptr;
node->next = nullptr;
head = node;
tail = head;
}
else {
// Case 2: There is more than one node
Node *curr = head;
if (curr->next != nullptr)
{
while (curr->next) {
// If the value is less than the current value
if (value < curr->data) {
Node *temp = new Node;
temp->data = curr->data;
temp->next = curr->next;
temp->prev = curr->prev;
node->next = temp;
node->prev = temp->prev;
curr->prev = node;
}
curr = curr->next;
}
}
// Case 3: There is only one node
else {
node->prev = head;
node->next = nullptr;
tail = node;
}
}
}
int main() {
dll<int> list;
list.insert(10);
list.insert(20);
list.insert(15);
}
The problem I am having is in my insert function. I am using the debugger and stepping into the code at the line: list.insert(10);.
It correctly goes into the first case where head == nullptr and creates the Node.
When I step into the next line of code (list.insert(20) ), it creates a node with this line: Node *node = new Node;
But it is creating the node with the memory address that head is pointing to.
I put a watch on the head variable and the node variable and the memory addresses were the same.Basically it is creating the same Node as it did for the last insertion.
I don't know how to get the line: Node *code = new Node; to create something new. Am I using the new keyword wrong here?

To make the initialization of Node easier, let's add a reasonable constructor that initializes prev and next members to null. That makes things easier for later code.
struct Node {
Node* prev;
Node* next;
T data;
Node() : prev(nullptr), next(nullptr)
{
}
};
There's always four cases to be aware of in a linked list problem. Some of which you got. Inserting into an empty list. Inserting at the front of the list, inserting at the end of the list, and the middle.
template <typename T> void dll<T>::insert(T value) {
Node *node = new Node;
node->data = value;
// Case 1: There are no nodes yet
if (head == nullptr) {
head = node;
tail = head;
return;
}
// case 2 - inserting at the head of the list
if (node->data < head->data)
{
node->next = head;
head = node;
return;
}
// case 3 - inserting at the end of the list
if (node->data >= tail->data)
{
node->prev = tail;
tail->next = node;
tail = node;
return;
}
// general case - inserting into the middle
Node* probe = head;
while (probe && (node->data >= probe->data))
{
probe = probe->next;
}
if (probe)
{
node->next = probe;
node->prev = probe->prev;
probe->prev->next = node;
probe->prev = node;
return;
}
// error - we shouldnt' reach this point. If we did, it meant the list was out of order to begin with.
return;
}

First of all the destructor is invalid. This statement
delete[] head;
means that head is an array. However head is not an array. It is a pointer to a single object of type Node. You have to delete all nodes of the list in the destructor. The destructor can look the following way
template <typename T>
dll<T>::~dll()
{
while ( head )
{
Node *tmp = head;
head = head->next;
delete tmp;
}
}
As for the method insert then it can look very simply. For example
template <typename T>
void dll<T>::insert( const T &value )
{
Node *current = head;
Node *previous = nullptr;
while ( current && !( value < current->data ) )
{
previous = current;
current = current->next;
}
Node *node = new Node { previous, current, value };
if ( previous == nullptr ) head = node;
else previous->next = node;
if ( current == nullptr ) tail = node;
else current->prev = node;
}
And there is no any need and reason to add a constructor to structure Node. It is better when it is an aggregate.
Here is a test program
#include <iostream>
template <typename T>
class dll
{
private:
struct Node
{
Node *prev;
Node *next;
T data;
};
Node *head;
Node *tail;
public:
dll();
~dll();
void insert( const T &value);
bool empty() const { return head == tail; };
void print() const;
};
template <typename T>
dll<T>::dll()
{
head = tail = nullptr;
}
template <typename T>
dll<T>::~dll()
{
while ( head )
{
Node *tmp = head;
head = head->next;
delete tmp;
}
}
template <typename T>
void dll<T>::insert( const T &value )
{
Node *current = head;
Node *previous = nullptr;
while ( current && !( value < current->data ) )
{
previous = current;
current = current->next;
}
Node *node = new Node { previous, current, value };
if ( previous == nullptr ) head = node;
else previous->next = node;
if ( current == nullptr ) tail = node;
else current->prev = node;
}
template <typename T>
void dll<T>::print() const
{
for ( Node *current = head; current; current = current->next )
{
std::cout << current->data << ' ';
}
}
int main()
{
dll<int> list;
list.insert( 10 );
list.insert( 20 );
list.insert( 15 );
list.print();
std::cout << std::endl;
return 0;
}
The output is
10 15 20

Related

Copy Constructor Error With a Template Linked List Class : no matching function for call to 'Node<int>::Node()'

I'm trying to make a copy constructor for a linked list but I'm not sure how to fix this error and I've been looking for hours. The error is:
no matching function for call to 'Node::Node()'
Here is the code:
template <class T>
class Node //node is the name of class, not specific
{
public:
T data; //t data allows for any type of variable
Node *next; //pointer to a node
Node(T Data) //assign data value
{
data = Data; //makes data = NV parameter
next = nullptr; //makes next = to nullptr
}
};
template <class T>
class LinkedList
{
private:
Node<T> * head, *tail; //// typedef Node* head // -- head = Node* -- //// typedef Node* nodePtr = Node* ////
public:
LinkedList() //constructor for Linked List
{
head = nullptr;
tail = nullptr;
}
LinkedList(LinkedList& copy)
{
head = nullptr;
tail = nullptr;
Node<T>* Curr = copy.head;
while(Curr) //while not at end of list
{
//val = copyHead->data;
Node<T>* newCpy = new Node<T>;
newCpy->data = Curr->data;
newCpy->next = nullptr;
if(head == nullptr)
{
head = tail = newCpy;
}
else
{
tail->next = newCpy;
tail = newCpy;
}
}
}
~LinkedList()
{
while (head)
{
Node<T>* tmp = head;
head = head->next;
delete(tmp);
}
head = nullptr;
}
The class Node does not have the default constructor. It has only the following constructor
Node(T Data) //assign data value
{
data = Data; //makes data = NV parameter
next = nullptr; //makes next = to nullptr
}
And in this statement
Node<T>* newCpy = new Node<T>;
there is used the default constructor that is absent.
At least instead of these three statements
//val = copyHead->data;
Node<T>* newCpy = new Node<T>;
newCpy->data = Curr->data;
newCpy->next = nullptr;
you need to write
//val = copyHead->data;
Node<T>* newCpy = new Node<T>( Curr->data );
Pay attention to that within the while loop
while(Curr)
{
//...
}
the pointer Curr is not changed. So the loop is infinite if Curr is not a null pointer
It seems you forgot to insert this statement
Curr = Curr->next;
before the closing brace of the loop.

Reverse a linked list using recursion

The void reve(struct Node *head) and display(struct Node *head) methods take one argument - the head of the linked list. I want to print the whole linked list but my display function print only 4.
#include <iostream>
using namespace std;
struct Node {
int data;
struct Node *link;
};
void display(struct Node *head) {
if (head == NULL) {
return;
}
cout << head->data << "\t";
display(head->link);
//head = head->link;
}
struct Node *reve(struct Node *head) {
struct Node *p = head;
if (p->link == NULL) {
head = p;
return head;
}
reve(p->link);
struct Node *temp = p->link;
temp->link = p;
p->link = NULL;
}
struct Node *insert(struct Node *head, int new_data) {
Node *new_node = new Node();
new_node->data = new_data;
new_node->link = head;
head = new_node;
return head;
}
int main() {
Node *head = NULL;
head = insert(head, 1);
head = insert(head, 2);
head = insert(head, 3);
head = insert(head, 4);
cout << "The linked list is: ";
//display(head);
head = reve(head);
display(head);
return 0;
}
Output
If you want the recursive way:
Node* reverse(Node* head)
{
if (head == NULL || head->next == NULL)
return head;
/* reverse the rest list and put
the first element at the end */
Node* rest = reverse(head->next);
head->next->next = head;
head->next = NULL;
/* fix the head pointer */
return rest;
}
/* Function to print linked list */
void print()
{
struct Node* temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
}
The function reve does not return a value if p->link is not NULL.
Since head has more than 1 element, head = reve(head); has undefined behavior.
Reversing a linked list is much easier to implemented in a simple loop than with recursion:
struct Node *reve(struct Node *p) {
if (p != NULL) {
struct Node *prev = NULL;
while (p->link) {
struct Node *next = p->link;
p->link = prev;
prev = p;
p = next;
}
}
return p;
}
If your task requires recursion, you can make a extract the first node, reverse the remainder of the list and append the first node. Beware that this is not tail recursion, hence any sufficiently long list may cause a stack overflow.
struct Node *reve(struct Node *head) {
if (head != NULL && head->link != NULL) {
struct Node *first = head;
struct Node *second = head->link;
head = reve(second);
first->link = NULL; // unlink the first node
second->link = first; // append the first node
}
return head;
}
In C++ you need not to use keywords struct or class when an already declared structure or a class is used as a type specifier.
The function reve has undefined behavior.
First of all head can be equal to nullptr. In this case this statement
if (p->link == NULL) {
invokes undefined behavior.
Secondly the function returns nothing in the case when p->link is not equal to nullptr.
//...
reve(p->link);
struct Node *temp = p->link;
temp->link = p;
p->link = NULL;
}
Here is a demonstrative program that shows how the functions can be implemented. I used your C approach of including keyword struct when the structure is used as a type specifier.
#include <iostream>
struct Node
{
int data;
struct Node *link;
};
struct Node * insert( struct Node *head, int data )
{
return head = new Node{ data, head };
}
struct Node * reverse( struct Node *head )
{
if ( head && head->link )
{
struct Node *tail = head;
head = reverse( head->link );
tail->link->link = tail;
tail->link = nullptr;
}
return head;
}
std::ostream & display( struct Node *head, std::ostream &os = std::cout )
{
if ( head )
{
os << head->data;
if ( head->link )
{
os << '\t';
display( head->link, os );
}
}
return os;
}
int main()
{
struct Node *head = nullptr;
const int N = 10;
for ( int i = 0; i < N; i++ )
{
head = insert( head, i );
}
display( head ) << '\n';
head = reverse( head );
display( head ) << '\n';
return 0;
}
The program output is
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
display is fine.
First thing I have notices is that you are trying to modify a copied value. For example, line 16. This code has no effect.
Note that you have a bug on insert: You return head instead of new_node.
Your version fails for lists with more than 1 item. reve() is supposed to return the last node of the original list, which you do not, hence lastNode would not point to the last node of the reversed list. So my advice is that you keep it aside.
So, reve:
struct Node* reve(struct Node* head) {
if (head->link == NULL) {
return head;
}
struct Node* lastNode = reve(head->link);
lastNode->link = head;
head->link = NULL;
return head;
}
and main:
int main() {
Node* head = NULL;
Node* last_node = head = insert(head, 1);
head = insert(head, 2);
head = insert(head, 3);
head = insert(head, 4);
head = reve(head);
cout << "The linked list is: ";
// Now, last_node is the new head
display(last_node);
return 0;
}

Linked List implementation of a Stack

Fairly new to implementing stacks and was looking for some possible feedback. My code gives the correct output, but I know this doesn't always mean it is working as it is suppose to. I chose to take the approach that implementing a stack using a linked list was essentially the same as your regular linked list implementation except that all the operations are done on the end of the list. I was not too sure if this approach was correct, but it followed the first in last out approach, and has the same complexity for access & search (O(n)) and insertion and deletion O(1). Such as pop() would just be deleting a node from the end of the linked list, and push() would just be appending a node to the end of the linked list. I have pasted my code below with comments within them explaining what I am doing or trying to do (if it is incorrect).
#include <iostream>
struct Node{
int data;
Node* next;
};
bool isEmpty(Node** stack){
if(*stack == NULL){
return true;
}
return false;
}
void push(Node** stack, int data){
Node* new_node = new Node();
new_node->data = data;
new_node->next=NULL;
// stack similar to "head"
if(isEmpty(&(*stack))){
*stack = new_node;
return;
}
Node* temp = *stack;
while(temp->next != NULL){
temp = temp->next;
}
temp->next = new_node;
}
void pop(Node** stack){
// checking if stack is empty
if(isEmpty(&(*stack))){
std::cout<<"Stack underflow"<<std::endl;
return;
}
Node* deleteMe = *stack;
// if at the first element in the stack
if(deleteMe->next == NULL){
*stack = (*stack)->next;
delete deleteMe;
return;
}
while(deleteMe->next != NULL){
if(deleteMe->next->next==NULL){
// saving the current location of the node before the node which I want to delete
Node* temp = deleteMe;
// updating the deleteMe pointer to the node which I want to delete
deleteMe = deleteMe->next;
// setting the current node before the deleteMe node to point to NULL instead of the node which I want to delete
temp->next = NULL;
delete deleteMe;
return;
}
deleteMe = deleteMe->next;
}
}
void printList(Node* stack){
Node* temp = stack;
while(temp!=NULL){
std::cout<<temp->data<<" ";
temp = temp->next;
}
std::cout<<"\n";
}
int top(Node** stack){
Node* top = *stack;
while(top->next!=NULL){
top = top->next;
}
return top->data;
}
int main(){
Node* stack = NULL;
// testing implementation below
push(&stack,10);
std::cout<<top(&stack)<<std::endl;
push(&stack,20);
std::cout<<top(&stack)<<std::endl;
push(&stack,30);
push(&stack,40);
printList(stack);
std::cout<<top(&stack)<<std::endl;
pop(&stack);
pop(&stack);
push(&stack,40);
std::cout<<top(&stack)<<std::endl;
}
Your implementation looks fine, one additional improvement can be done by maintaining head and tail pointer so that you can remove 1st and last element as needed. Here is example c++ code.
#include <iostream>
using namespace std;
template <class T> class node {
public:
node<T>() {}
~node<T>() {}
T data;
node<T> *next;
};
template <class T> class linked_list {
public:
linked_list<T>() : head(NULL), tail(NULL) {}
~linked_list<T>() {}
virtual void addFirst(T data) {
node<T> *n = new node<T>();
if (head == NULL)
tail = n;
n->data = data;
n->next = head;
head = n;
size++;
}
virtual void addLast(T data) {
node<T> *n = new node<T>();
n->data = data;
if (tail == NULL) {
head = n;
} else {
tail->next = n;
}
n->next = NULL;
tail = n;
}
virtual void reverse() {
if ((head == NULL) || (head->next == NULL))
return;
node<T> *current = head;
node<T> *previous = NULL;
node<T> *next = current->next;
tail = current;
while (current) {
next = current->next;
current->next = previous;
previous = current;
current = next;
}
head = previous;
}
virtual void print_nodes() {
node<T> *temp = head;
while (temp) {
cout << temp->data << " " << flush;
temp = temp->next;
}
cout << endl;
}
virtual void removeLast() {
node<T> *temp = head;
while (temp->next->next) {
temp = temp->next;
}
tail = temp;
delete temp->next;
temp->next = NULL;
}
virtual void removeFirst() {
node<T> *temp = head;
head = head->next;
delete temp;
}
private:
node<T> *head;
node<T> *tail;
uint32_t size;
};
int main(int argc, const char *argv[]) {
linked_list<uint32_t> *llist = new linked_list<uint32_t>();
llist->addLast(1);
llist->addFirst(5);
llist->addFirst(10);
llist->addFirst(15);
llist->addFirst(20);
llist->addLast(30);
llist->addFirst(40);
llist->print_nodes();
llist->reverse();
llist->print_nodes();
llist->removeLast();
llist->print_nodes();
llist->removeFirst();
llist->print_nodes();
return 0;
}

Struggling to transfer a doubly linked generic list to circular. (segfault)

So I've got this non-circular doubly linked list sample and I find it rather hard to transfer it to a circular one. (segfaulting on the //added lines)
Any advise would be nice.
Thanks in advance.
Also, should I use overloading to handle input of different types? How do I manipulate them? A link with a proper example (really couldn't find one) would make me happy.
main.cpp
#include <iostream>
#include "dlring.cpp"
int main()
{
dlring<int> dlist;
dlist.Append( 11 );
dlist.Push( 100 );
while(dlist)
std::cout << dlist.pop_back() << " ";
}
dlring.h
template <typename T>
class dlring
{
struct node
{
T data;
node* prev;
node* next;
node(T t, node* p, node* n) : data(t), prev(p), next(n) {}
};
node* head;
node* tail;
public:
dlring() : head(nullptr), tail (nullptr) {}
bool empty() const { return ( !head || !tail ); }
operator bool() const { return !empty(); }
//Yes, I also wish to implement this bool stuff otherwise.
void Append(T);
void Push(T);
T pop_back();
T pop_front();
~dlring()
{
while(head)
{
node* temp(head);
head=head->next;
delete temp;
}
}
};
dlring.cpp
#include "dlring.h"
#include <iostream>
template <typename T>
void dlring<T>::Append(T data)
{
tail = new node(data, tail, head); //changed NULL=>head
if( tail->prev )
{
tail->prev->next = tail;
head->prev = tail; //added
}
if( empty() )
head = tail;
}
template <typename T>
void dlring<T>::Push(T data)
{
head = new node(data, tail, head); //changed NULL=>tail
if( head->next )
{
head->next->prev = head;
tail->next = head; //added
}
if( empty() )
tail = head;
}
template<typename T>
T dlring<T>::pop_back()
{
if( empty() )
std::cout<<"List empty";
node* temp(tail);
T data( tail->data );
tail = tail->prev ;
if( tail )
{
tail->next = head; //null=>head;
head->prev = tail; //added
}
else
head = nullptr; //NULL=>nullptr
delete temp;
return data;
}
template<typename T>
T dlring<T>::pop_front()
{
if( empty() )
std::cout<<"List empty";
node* temp(head);
T data( head->data );
head = head->next ;
if( head )
{
head->prev = tail; //NULL=>nullptr=>tail
tail->next = head;
}
else
tail = nullptr; //NULL=>nullptr
delete temp;
return data;
}
You problem is in the pop_back function:
node * temp(tail);
T data(tail->data);
tail = tail->prev;
if(tail)
{
tail->next = head; //null=>head;
head->prev = tail; //added
}
else
{
head = nullptr; //NULL=>nullptr
}
delete temp;
When there is only one node in the list, tail isn't null - this means the if condition will be met, and the code below will be hit:
tail->next = head; //null=>head;
head->prev = tail; //added
But this code does nothing, because tail and head are the same thing. You then delete the only node in the list, and head and tail no longer point to anything. To solve this, you need a better way to detect if the list will be empty after deletion, and to alter the deletion code a bit:
if (tail != temp)
{
tail->next = head; //null=>head;
head->prev = tail; //added
}
else
{
head = nullptr; //NULL=>nullptr
tail = nullptr;
}
delete temp;
temp = nullptr;

changing linked list into a doubly linked list

Hi could you please help me change this linked list into a doubly linked list ?
I would be very grateful for help :)
#include <iostream>
using namespace std;
template <class T>
struct node
{
T data;
node<T> *next;
node<T> *prev;
};
template <class T>
class Container
{
public:
//constructs a new empty Kontener
Container()
{
head = new node<T>;
head->next = head;
head->prev = head;
};
//constructs a new jp_list that is a copy of an existing list
Container(const Container<T>& rt_side)
{
head = new node<T>;
head->next = head;
head->prev = head;
node<T> *crt_ptr = rt_side.head->next;
while(crt_ptr != rt_side.head)
{
push_back(crt_ptr->data);
crt_ptr = crt_ptr->next;
}
};
//adds a data node to the front of the list
void push_front(T nw_data)
{
node<T> *temp = new node<T>;
temp->data = nw_data;
temp->next = head->next;
head->next->prev = temp;
temp->prev = head;
head->next = temp;
};
//adds a data node to the end of the list
void push_back(T nw_data)
{
node<T> *temp = new node<T>;
temp->data = nw_data;
head->prev->next = temp;
temp->prev = head->prev;
temp->next = head;
head->prev = temp;
};
//removes the first node and returns the data
T pop_front()
{
node<T> *temp = head->next;
T temp_data = head->next->data;
head->next = temp->next;
temp->next->prev = head;
delete temp;
return temp_data;
};
//removes the last node and returns the data
T pop_back()
{
node<T> *temp = head->prev;
T temp_data = head->prev->data;
head->prev = temp->prev;
temp->prev->next = head;
delete temp;
return temp_data;
};
//resturns the size of the list
int size()
{
int size = 0;
node<T> *crt_ptr; //pointer to current node
crt_ptr = head->next;
while(crt_ptr != head)
{
size += 1;
crt_ptr = crt_ptr->next; //advance to the next node then loop
}
return size;
};
//prints out all the data in the list
void display_all()
{
node<T> *crt_ptr = head->next;
for(int i = 0; crt_ptr != head; i++)
{
cout << "Node " << (i+1) << ": " << crt_ptr->data << endl;
crt_ptr = crt_ptr->next;
}
};
Container& operator= (const Container& rt_side)
{
if(this == &rt_side)
return *this;
node<T> *crt_ptr = head->next;
//empty this list so the rt_side can be coppied in
while(crt_ptr != head)
{
crt_ptr = crt_ptr->next;
pop_front();
}
crt_ptr = rt_side.head->next;
while(crt_ptr != rt_side.head)
{
push_back(crt_ptr->data);
crt_ptr = crt_ptr->next;
}
return *this;
};
virtual ~Container()
{
int list_size = size();
for(int i = 0; i < list_size; i++)
{
pop_front();
}
delete head;
};
private:
node<T> *head;
};
#endif
I am just a beginner so please help me :)
The tail would always point to the last item that was inserted into the list.
However, I do not think that having a tail pointer makes it necessarily a doubly linked list. A singly linked list can also have a tail pointer (however useless it might be). I believe you are asking to create a double ended doubly linked list.
You already have the next and previous pointers to enable the double link. All you have to do, is when you push something into the list, you need to make the tail pointer point to the node that is being added. Similarly, when removing a node, you need the tail pointer to point to tail's previous BEFORE deleting the last node.
* UPDATE *
Here is some code. I am assuming a double ended doubly linked list with two ends.
void push_front(T nw_data)
{
node<T> *temp = new node<T>;
temp->data = nw_data;
if(head == nullptr)
{
head = temp;
tail = temp;
}
else if(head == tail)
{
head->next = temp;
temp->prev = head;
tail = temp;
}
else
{
temp->next = head->next;
head->next->prev = temp;
temp->prev = head;
head->next = temp;
}
};
//adds a data node to the end of the list
void push_back(T nw_data)
{
node<T> *temp = new node<T>;
temp->data = nw_data;
if(head == nullptr)
{
head = temp;
tail = temp;
}
else if(head == tail)
{
head->next = temp;
temp->prev = head;
tail = temp;
}
else
{
temp->prev = tail;
tail->next = temp;
tail = temp;
}
};
T pop_back()
{
node<T> *temp = tail;
T temp_data = tail->data;
tail = tail->prev;
tail->next = null;
delete temp;
return temp_data;
};
* UPDATE * Copy Constructor
In your copy constructor, if the push_back sets the tail, then all you need to do is to push_back the nodes like you are doing. head->next = head and head->prev = head makes the linked list cyclical.
Container(const Container<T>& rt_side)
{
this->head = rt_side.head;
node<T> * crt_ptr = rt_side.head->next;
while (crt_ptr != null)
{
push_back(crt_ptr->data);
crt_ptr = crt_ptr->next;
}
};