Doubly linked list class - c++

I am trying to make a double linked list. Function push(int x) should add a node to the list and make the correct link. I use:
class Node {
public:
int value;
Node* next;
Node* prev;
public:
Node() {}
void set_value(int x) { value = x; }
void set_next(Node* x) { next = x; }
void set_prev(Node* x) { prev = x; }
Node* get_next() { return next; }
Node* get_prev() { return prev; }
};
class deque {
public:
Node* head;
Node* tail;
public:
deque() { head = NULL; tail = NULL; }
void push(int x) {
Node* n = new Node();
n->set_value(x);
n->set_next(NULL);
n->set_prev(NULL);
Node* t = head; //link to the next node
if (t == NULL) {
head = n;
} else {
while (t->get_next() != NULL) {
t = t->get_next();
}
t->set_next(n);
}
}
};
As I have tested the part that connects a node to the next one works fine but I am having some troubles connecting the node to the previous one. One that comes in mind is a variation of the first one:
Node* t = tail;
if (t == NULL) {
tail = n;
} else {
while (t->get_prev() != NULL) {
t = t->get_prev();
}
t->set_prev(n);
}
But by using this, the tail node is always the current n node if only the node n is the one and only node in the queue... What should I do? thanks a lot

Drawing always helps with such data structures. What you have currently:
You correctly set t's next with: t->set_next(n);. What is missing is the arrow underneath it, and it's: n->set_prev(t).
In general, when dealing with doubly-linked lists, a call to set_next should always (most of the time) be accompanied by a call to set_prev on set_next's argument. It's because of the doubly-linked list's property:
x->next == y implies y->prev == x, and y->prev == x implies x->next == y.

Related

const function modifying data in Doubly Linked List

I have created a doubly linked list.
in the list, there is a function that is const, and is not supposed to modify the object. but it is modifyind I dont know why.
#include<iostream>
using namespace std;
class Node {
public:
int data;
Node* prev;
Node* next;
Node(int val) :data(val), next(NULL), prev(NULL) {}
};
class List {
Node* head;
Node* tail;
public:
List() :head(NULL), tail(NULL) {}
void addToTail(int val) {
Node* temp = new Node(val);
if (head == NULL) {
head = temp;
tail = temp;
}
else {
tail = head;
while (tail->next != NULL) {
tail = tail->next;
}
tail->next = temp;
temp->prev = tail;
tail = temp;
}
}
int search(int val) const
{
if (head->data == val)
head->data = 12;
return head->data;
}
};
int main()
{
List l;
l.addToTail(1);
l.addToTail(2);
l.addToTail(3);
l.addToTail(4);
l.addToTail(5);
int c = l.search(1);
//c = 102;
cout << c;
}
Now I have tried to use const before the return type, but obviously it doesnt matter. it does not affect the result;
in the search(int val) function, I am sending a value to check if 'head->data' is equal to the 'val', it should not modify the 'head->data = 12' because the function is const. but it is doing this.
The const qualifier for the member function only tells the compiler that you won't modify this object.
And you don't do that: You modify head->data which is another object.
It would be a different issue if you tried to reassign the variables head or tail.

Linked List insertion isn't working in for/while loop

I am learning DSA, and was trying to implement linked list but the insertion function that i wrote is not
working in a for or while loop, its not the same when i call that function outside the loop, it works that way. I am not able to figure it out, please someone help me.
#include <iostream>
class Node {
public:
int data;
Node *next;
Node(int &num) {
this->data = num;
next = NULL;
}
};
class LinkedList {
Node *head = NULL;
public:
void insert(int num) {
Node *tmp;
if (head == NULL) {
head = new Node(num);
tmp = head;
} else {
tmp->next = new Node(num);
tmp = tmp->next;
}
}
void printList() {
Node *tmp = head;
while (tmp) {
std::cout << tmp->data << " ";
tmp = tmp->next;
}
std::cout << std::endl;
}
void reverseList() {
Node *curr = head, *prev = NULL, *nextNode;
while (curr) {
nextNode = curr->next;
curr->next = prev;
prev = curr;
curr = nextNode;
}
head = prev;
}
};
int main() {
LinkedList list1;
// This is not working
int num;
while (num != -1) {
std::cin >> num;
list1.insert(num);
}
// This is working
// list1.insert(1);
// list1.insert(2);
// list1.insert(3);
// list1.insert(4);
// list1.insert(5);
list1.printList();
list1.reverseList();
list1.printList();
return 0;
}
I expect this after insertion
Edit:
although #Roberto Montalti solved this for me, but before that I tried passing incrementing value using a for loop which worked but as soon as I pull that cin out it crashes. can someone tell me what's happening under the hood?
for (int i = 1; i <= 10; i++)
{
list1.insert(i);
}
When inserting the nth item (1st excluded) tmp is a null pointer, i don't understand what you are doing there, you are assigning to next of some memory then you make that pointer point to another location, losing the pointer next you assigned before, you must keep track of the last item if you want optimal insertion. This way you are only assigning to some *tmp then going out of scope loses all your data... The best way is to just keep a pointer to the last inserted item, no need to use *tmp.
class LinkedList
{
Node *head = NULL;
Node *tail = NULL;
public:
void insert(int num)
{
if (head == NULL)
{
head = new Node(num);
tail = head;
}
else
{
tail->next = new Node(num);
tail = tail->next;
}
}
...
}
You need to loop until you reach the end of the list and then add the new node after that. Like this.
void insert(int num) {
Node *tmp = head;
if (head == NULL) {
head = new Node(num);
}
else {
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = new Node(num);
}
}
first of all you need to define a node for each of the tail and head of the list as follows
Node *h;
Node *t;
you may also separate the Node from the LinkedList class so you can modify easily
class Node{
public:
int data;
Node *next;
Node(int data, Node* next);
~Node();
};
Node::Node(int data, Node* next)
{
this->data= data;
this->next= next;
}
Node::~Node(){}
}
after that you can try to add these functions to your LinkedList class
so it can deal with other special cases such empty list or full, etc..
void addToHead(int data){
Node *x = new Node(data,h);
h=x;
if(t==NULL){
t=x;
}
void addToTail(int data){
Node *x = new Node(data,NULL);
if(isEmpty()){
h=t=x;
}
else
{
t->next=x;
t=x;
}
}
now for the insert function try this after you implemented the Node class and the other functions,
void insert(int v){
if(h==nullptr){addToHead(v); return;}
if(h->data>=v) {addToHead(v);return;}
if(t->data<=v) {addToTail(v); return;}
// In this case there is at least two nodes
Node *k=h->next;
Node *p=h;
while(k != nullptr){
if(k->data >v){
Node *z =new Node(v,k);
p->next=z;
return;
}
p=k;
k=k->next;
}
}
the idea of making all of this is not lose the pointer when it goes through elements in the Linked List so you don't end up with a run time error.
I hope this can be useful to you.
There was an issue with your insert function.
Read about segmentation fault here https://www.geeksforgeeks.org/core-dump-segmentation-fault-c-cpp/#:~:text=Core%20Dump%2FSegmentation%20fault%20is,is%20known%20as%20core%20dump.
for a quick workaround you can use this
using namespace std;
#include <iostream>
class Node
{
public:
int data;
Node *next;
Node(int num)
{
this->data = num;
next = NULL;
}
};
class LinkedList
{
Node *head = NULL;
public:
void insert(int num)
{
Node *tmp= new Node(num);
tmp->next=head;
head=tmp;
}
void printList()
{
Node *tmp = head;
while (tmp)
{
std::cout << tmp->data << " ";
tmp = tmp->next;
}
std::cout << std::endl;
}
void reverseList()
{
Node *curr = head, *prev = NULL, *nextNode;
while (curr)
{
nextNode = curr->next;
curr->next = prev;
prev = curr;
curr = nextNode;
}
head = prev;
}
};
int main()
{
LinkedList list1;
// This is not working
int num,i=0,n;
cout<<"Type the value of n";
cin>>n;
while (i<n)
{
cin >> num;
cout<<num<<" "<<&num<<endl;
list1.insert(num);
i++;
}
list1.printList();
list1.reverseList();
list1.printList();
return 0;
}

Do I need to delete a dynamically allocated object in Singly Linked List?

I am currently learning Linked Lists and have implemented a singly linked list with Append and Prepend methods where I have allocated objects of type Node on heap using the 'new' operator. Do I need to deallocate the object on heap using 'delete', and if so then how do I do it ?
Here is my code:-
class List
{
private:
class Node
{
public:
int data;
Node* next;
Node()
{
data = 0;
next = NULL;
}
Node(const int& data)
{
this->data = data;
}
};
Node* head;
public:
List()
{
head = NULL;
}
void Append(const int&val);
void Prepend(const int&val);
void DisplayAll();
};
void List::Append(const int&val)
{
Node* n = new Node(val); //dynamically allocated
if (head == NULL)
{
head = n;
return;
}
Node* temp = NULL;
temp = head;
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = n;
}
void List::Prepend(const int&val)
{
Node* node = new Node(val);//dynamically allocated
if (head == NULL)
{
head = node;
return;
}
node->next = head;
head = node;
}
void List::DisplayAll()
{
Node* temp = head;
while (temp != NULL)
{
std::cout << temp->data << ' ';
temp = temp->next;
}
}
For starters this constructor
Node(const int& data)
{
this->data = data;
}
does not initialize the data member next. As a result member functions Append and Prepend have a bug
void List::Append(const int&val)
{
Node* n = new Node(val); //dynamically allocated
if (head == NULL)
{
head = n;
return;
}
//...
and
void List::Prepend(const int&val)
{
Node* node = new Node(val);//dynamically allocated
if (head == NULL)
{
head = node;
return;
}
//...
The data member next of the head node has an indeterminate value.
You could declare the class Node simpler like
struct Node
{
int data;
Node* next;
};
Node* head = nullptr;
In this case for example the function Prepend will look like
void List::Prepend( const int &val )
{
head = new Node { val, head };
}
And the constructor will look like
List() = default;
To free all allocated nodes in the list you could write two more member functions clear and the destructor that calls the function clear.
For example
#include <functional>
//...
class List
{
//...
public:
void clear()
{
while ( head ) delete std::exchange( head, head->next );
}
~List() { clear(); }
//...
Also you should at least either write a copy constructor and the copy assignment operator or define them as deleted.

Linked-list program crashing after adding elements

My program crashes after sequence of inserting head, then inserting tail, every other cases it seems to work. I cant figure it out.
struct Node {
int key;
Node *next;
};
struct List {
Node *head, *tail;
};
void init(List& l) {
l.head = l.tail = NULL;
}
void insertHead(List& l, int x) {
Node *temp=new Node;
temp->next=NULL;
temp->key=x;
temp->next=l.head;
l.head=temp;
}
void insertTail(List& l, int x) {
Node *temp=new Node;
temp->key=x;
temp->next=NULL;
if(l.head==NULL) {
l.head = temp;
l.tail = temp;
} else {
l.tail->next=temp;
l.tail=temp;
}
}
Thats only part of my code, but I think it will be enough, otherwise here is remaining part http://pastebin.com/WxmYJ0uE
You forgot to set the tail when the first element in the list in inserted.
void insertHead(List& l, int x) {
Node *temp=new Node;
temp->next=NULL;
temp->key=x;
temp->next=l.head;
l.head=temp;
if(l.tail == NULL) l.tail = l.head; // <-- you forgot this
}

Logic Correct but Program Crashes

NOTE: This question is not about reversing a linked list using recursion but about why it crashes. It's more about dynamic memory really.
I'm implementing a linked list and want to have a function in it that recursively reverses it.
struct sNode {
int data;
sNode* next;
sNode(int x) {
data = x;
next = 0;
}
sNode(int x, sNode* n) {
data = x;
next = n;
}
};
class SLL {
public:
SLL() : head(0) {}
sNode* getHead() { return head;}
void reverseRec(sNode*); // Reverse the list using recursion;
private:
sNode* head;
};
void SLL::reverseRec(sNode* node) {
// Reverse the list using recursion
if (node == 0) {
head = node;
return;
}
reverseRec(node->next);
sNode* temp = node->next;
temp->next = node;
node->next = 0;
}
int main() {
SLL l1;
l1.addAtEnd(1);
l1.addAtBeg(2);
l1.addAtPos(3, 2);
l1.reverseRec(l1.getHead());
return 0;
}
The program just crashes. Please help me figure out the reason. I think it's got to do with the arguments of the function.
This is a problem.
if (node == 0) {
head = node;
return;
}
You just made the list an empty list. That should be (prefer to use nullptr or NULL instead of 0 for pointers):
if (node == nullptr || node->next == nullptr ) {
head = node;
return;
}