My function to remove nodes from a doubly linked list is adding (overwriting?) values to the list, which appear when the list is printed.
Code for the main, remove and print functions is listed below. The expected output and correlations between the current code and its output are shown below too.
Code for main
In main, the add function is called, and the integer in the parameter is added as a node in the linked list. The add function works, as does the print function.
int main()
{
LinkedList aList;
aList.add(3);
aList.add(10);
aList.add(1);
aList.add(7);
aList.add(9);
aList.add(12);
aList.printAscending();
aList.printDescending();
aList.remove(3);
aList.remove(1); //The integer to be removed with this line ends up in the output
aList.remove(7);
aList.remove(12);
cout << "remove operations should be complete" <<endl;
aList.printAscending();
aList.printDescending();
return 0;
}
Code for remove function
bool LinkedList::remove(int val) //parameter contains value to be removed
{
bool removed = false;
Node* newNode = new Node;
newNode->data = val;
newNode->next = NULL;
newNode->prev = NULL;
Node* curr = head;
while(curr)
{
if(curr->data == val)
{
if(curr == head)
{
head = head->next;
curr->next = NULL;
delete curr;
}
else if(curr != head && curr != tail)
{
Node * previous = curr->prev;
Node * following = curr->next;
previous->next = following;
following->prev = previous;
curr->next = NULL;
curr->prev = NULL;
delete curr;
}
else if(curr == tail)
{
tail = tail->prev;
curr->prev = NULL;
delete curr;
}
removed = true;
}
curr = curr->next;
}
return removed;
}
Code for print functions
//Prints from head to tail of list
void LinkedList::printAscending() const
{
Node* curr = head;
cout<<"\nascending: ";
while(curr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout <<'\n';
}
//Prints from tail to head of list
void LinkedList::printDescending() const
{
Node* curr = tail;
cout << "\ndescending: ";
while(curr)
{
cout << curr->data << " ";
curr = curr->prev;
}
cout << endl;
}
Expected output
ascending: 3 10 1 7 9 12
descending: 12 9 7 1 10 3
remove operations should be complete
ascending: 10 9
descending: 9 10
Actual Output
ascending: 3 10 1 7 9 12 //correct
descending: 12 9 7 1 10 3 //correct
remove operations should be complete //correct
ascending: 10 9 0 //last number, 0, is incorrect
descending: 9 10 1 //last number, 1, is incorrect
If the call in int main to remove the integer 1 aList.remove(1) is replaced with aList.remove(999), the integer 999 appears in the actual output on the descending print instead of 1. However, the integer 0 is appended to the ascending print at all times.
As well as the undefined behavior that Beta pointed out, you have a problem with both your special cases for head and tail. Running this through a debugger and inspecting the values in your list after each deleted would have shown you what is going wrong.
This code:
else if(curr == tail)
{
tail = tail->prev;
curr->prev = NULL;
delete curr;
}
does not do anything with the next pointer of the second last element. This means your second last element (which then becomes the last element) has a next pointer that points to freed memory.
To fix it, you need to set the second last element's next pointer to null. Something like this:
else if(curr == tail)
{
tail = tail->prev;
tail->next = NULL;
curr->prev = NULL;
delete curr;
}
But wait! There is (almost*) no guarantee that the previous element existed (i.e. in a 1 element list), so you need to check that the new tail is not NULL.
else if(curr == tail)
{
tail = tail->prev;
if (tail != NULL)
tail->next = NULL;
curr->prev = NULL;
delete curr;
}
*Actually if this was a single element list, you would not reach this code, you would have already gone through the "head" if test code, which has a similar problem in that it doesn't change the second node's prev pointer.
So you need to also do the same sort of test in the "head" if test code.
Once you have done that, you might find that you can rearrange the tests to get rid of repeated code.
After you delete curr, you then dereference it:
curr = curr->next;
This is undefined behavior.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
Im trying to create function to delete from single-linked list all elements with value smaller as next (following) element value. For some reason programm throws "free():double free detected in tcache 2". What is wrong with my function ?
list is not empty.
#include <iostream>
using namespace std;
struct Elem
{
int num;
Elem* next;
};
void deleteFromLinkedList(Elem* list) {
Elem* curr, * next, *prev;
curr = list;
next = list->next;
while (next != NULL)
{
if (curr->num < next->num) {
prev->next=next;
delete curr;
curr = prev;
continue;
}
prev = curr;
curr = next;
next = curr->next;
};
}
int main()
{
Elem* first = NULL, * last = NULL, * p;
int i;
cout << "Enter any number or 0 to finish: ";
cin >> i;
while (i != 0)
{
p = new Elem;
p->num = i;
p->next = NULL;
if (first == NULL)
{
first = last = p;
}
else
{
last->next = p;
last = last->next;
};
cout << "Enter any number or 0 to finish: ";
cin >> i;
};
deleteFromLinkedList(first);
There are a number of problems with your code.
next = list->next; is undefined behavior if the list is empty (ie list is null).
prev->next=next; is undefined behavior for the 1st node in the list, as prev is unassigned.
You are not updating curr after delete'ing the node it points at, which is also undefined behavior.
The list pointer is being passed in by value, so the caller's pointer can't be updated if the 1st node in the list is freed, thue the caller will be left with a dangling pointer to invalid memory.
Try this instead:
void deleteFromLinkedList(Elem* &list) {
if (!list)
return;
Elem *curr = list, *next = list->next, *prev = NULL;
while (next)
{
if (curr->num < next->num) {
if (prev)
prev->next = next;
else
list = next;
delete curr;
}
else {
prev = curr;
}
curr = next;
next = curr->next;
}
}
Online Demo
UPDATE: In comments, you changed your requirements to need the list scanned in multiple iterations. The code above works fine for 1 iteration, so you could simply call it multiple times in a loop until there are no more removals performed, eg:
bool deleteFromLinkedList(Elem* &list) {
if (!list)
return false;
Elem *curr = list, *next = list->next, *prev = NULL;
bool anyRemoved = false;
while (next)
{
if (curr->num < next->num) {
if (prev)
prev->next = next;
else
list = next;
delete curr;
anyRemoved = true;
}
else {
prev = curr;
}
curr = next;
next = curr->next;
}
return anyRemoved;
}
...
while (deleteFromLinkedList(first));
...
Online Demo
I have been trying to practice a bit with some algorithms and in my code for a doubly linked list, I want to be able to delete a node at nth position recursively. I have tried doing this on my own but I cannot seem to find an effective way of doing so with recursion. If someone could possibly help me out in doing so that would be great. Here is the code I have so far.
Additionally, I am also aware that the current code I have for my delete function only works for a singly linked list. I figured this out on my own and just put it there as a placeholder / messing around with the code I have written below.
#include <cctype>
using namespace std;
struct Node{
int data;
Node* next;
Node* prev;
};
Node* add(Node* head, int data);
void display(Node* head);
void displayReverse(Node* head);
Node* deleteNode(Node* head, int pos, Node* delNode);
int main(){
Node* head = NULL;
head = add(head, 1);
head = add(head,2);
head = add(head, 3);
head = add(head, 4);
head = add(head, 5);
display(head);
cout<<endl;
displayReverse(head);
cout<<endl;
int del;
cout<<"pos to delete: ";
cin>>del;
Node* delNode = NULL;
head = deleteNode(head, del, delNode);
display(head);
return 0;
}
Node* add(Node* head, int data){
if(head==NULL){ //if list is empty
Node* newNode = new Node;
newNode->data = data;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
else if(head!=NULL && head->next == NULL){ //if the head points to a node that has a next that is not empty, but the node at the next is empty, then add to the end of list
Node* newNode = new Node;
head->next = newNode;
newNode->data = data;
newNode->next = NULL;
newNode->prev = head;
}
else{ //if the head does not equal null, and the head next does not equal null either
head->next = add(head->next, data);
}
return head;
}
void display(Node* head){
if(head!=NULL){
cout<<head->data<<" ";
display(head->next);
}
return;
}
void displayReverse(Node* head){ //checks if the nodes are actually linked (this implementation works)
while(head->next!=NULL){
head = head->next;
}
while(head!=NULL){
cout<<head->data<< " ";
head = head->prev;
}
}
Node* deleteNode(Node* head, int pos, Node* delNode){
if(pos = 1){
delNode = head->next;
delete head;
return delNode;
}
else{
head->next = deleteNode(head->next, pos-1, delNode);
return head;
}
}
To delete nth node from a doubly linked list recursively :
Maintain a counter
If counter is less than position of node to be delete then
Increment the counter and recursive call the delete function and pass the next of current processing node in the list.
Assign the return value of delete function to next pointer of current processing node.
Reset the previous pointer of returned node from delete function.
Return the current processing node.
If counter is equal to the position that means the current node is to be delete from list
Record the next node of current processing node.
Reset next and previous links of current processing node to NULL.
Deallocate the current processing node node.
Reset the counter, so that (counter == position) condition will fail in further iterations.
Return the recorded node.
Implementation:
Node* deleteNode (Node* head, int pos) {
static int cnt;
if (head == NULL) {
return NULL;
}
if (++cnt < pos) {
head->next = deleteNode (head->next, pos);
if (head->next) {
// reset the pointer
head->next->prev = head;
}
}
if (cnt == pos) {
Node *tmp = head->next;
head->prev = NULL;
head->next = NULL;
free (head);
// reset counter
cnt = 0;
if (tmp) {
tmp->prev = NULL;
}
return tmp;
}
return head;
}
Output:
# ./a.out
1 2 3 4 5
5 4 3 2 1
pos to delete: 2
1 3 4 5
# ./a.out
1 2 3 4 5
5 4 3 2 1
pos to delete: 1
2 3 4 5
# ./a.out
1 2 3 4 5
5 4 3 2 1
pos to delete: 5
1 2 3 4
For invalid position :
# ./a.out
1 2 3 4 5
5 4 3 2 1
pos to delete: 8
1 2 3 4 5
Additional:
1). Avoid adding using namespace std; in your program. Check this.
I was solving the Print in reverse challenge on Hackerrank
The void ReversePrint(Node* head) method takes one argument - the head of the linked list. You should NOT read
any input from stdin/console. The head may be empty so nothing should be printed. Print the elements of the linked list in reverse order to
stdout/console (using printf or cout) , one per line.
Sample Input
1 --> 2 --> NULL
2 --> 1 --> 4 --> 5 --> NULL
Sample Output
2
1
5
4
1
2
I solved it using this
#include <vector>
void ReversePrint(Node *head)
{
// This is a "method-only" submission.
// You only need to complete this method.
std::vector<int> nodeList;
if(head != NULL){
while(head != NULL){
nodeList.push_back(head->data);
head = head->next;
}
for (std::vector<int>::iterator it = nodeList.end()-1 ; it != nodeList.begin()-1; --it){
std::cout << *it <<endl;
}
}
}
It works perfectly but extending to use recursion provides the wrong answer, why is this happening?
std::vector<int> nodeList;
void ReversePrint(Node *head){
if(head != NULL){
nodeList.push_back(head->data);
ReversePrint(head->next);
}
else{
for (std::vector<int>::iterator it = nodeList.end()-1 ; it != nodeList.begin()-1; --it){
std::cout << *it <<endl;
}
}
}
the result is
2
1
5
4
1
2
2
1
NB: The structure of the Node is given as
struct Node
{
int data;
struct Node *next;
}
Why so complicated?
/* Function to reverse print the linked list */
void ReversePrint(Node* head)
{
// Base case
if (head == NULL)
return;
// print the list after head node
ReversePrint(head->next);
// After everything else is printed, print head
std::cout << head->data << '\n';
}
In case, you want to return reversed linked list:
Node* List::reverseList()
{
if(head == NULL) return;
Node *prev = NULL, *current = NULL, *next = NULL;
current = head;
while(current != NULL){
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
You can reverse the linked list recursively then print the linked list.
Node* reverse(Node* node)
{
if (node == NULL)
return NULL;
if (node->next == NULL)
{
head = node;
return node;
}
Node* temp= reverse(node->next);
temp->next = node;
node->next = NULL;
return node;
}
I have encountered a problem printing sorted linked lists after deleting those values that are repeating more than 1 time.
Code:
Node* RemoveDuplicates(Node *head)
{
Node *prev,*cur;
cur=head;
while(cur->next!=NULL)
{
prev = cur;
cur = cur->next;
if(prev->data == cur->data)
{
prev->next = cur->next;
free(cur);
}
}
return head;
}
This deletes values that occur more than once, but for more than that it does not work and I am unable to find why.
Test cases:
For eg : if INPUT is like this :
4
6
1 2 2 3 3 4
7
1 1 1 1 1 1 1
5
2 3 3 4 6
1
10
Then it should have OUTPUT like this :
1 2 3 4
1
2 3 4 6
10
But my OUTPUT is :
1 2 3 4
1 1 1 1
2 3 4 6
10
As cur is freed,it could not be accessed in while.
You can do like this:
Node* RemoveDuplicates(Node *head)
{
if(head==NULL){
return NULL;
}
Node *prev,*cur;
cur=head;
while(cur->next!=NULL)
{
prev = cur;
cur = cur->next;
if(prev->data == cur->data)
{
prev->next = cur->next;
free(cur);
cur = prev;
}
}
return head;
}
This is one possible method. The basic idea is to walk the list and as long as there is a next node and the data matches snip the next node out of the list. I've added a DeleteNode() helper function that frees a node and returns it's old next pointer. This utility is useful in other contexts.
Node* DeleteNode(Node *node)
{
Node *ptr = node->next;
delete node; // This is C++, you might need free() instead
return ptr;
}
Node* RemoveDuplicates(Node *list)
{
Node *node = list;
while (node) {
while (node->next && (node->data == node->next->data)) {
node->next = DeleteNode(node->next);
}
node = node->next;
}
return list;
}
Here is a revamped version of your code which I believe will run without problems. I added a NULL check at the beginning and I modified the algorithm to correctly handle duplicates:
Node* RemoveDuplicates(Node *head)
{
if (head == NULL) // return NULL in case of empty list
return NULL;
if (head->next == NULL) // return the head in case of list with only one element
return head;
Node *prev,*cur;
prev = head;
cur = head->next;
while (cur != NULL)
{
if (prev->data != cur->data) {
prev->next = cur;
prev = cur;
cur = cur->next;
}
else {
Node* temp = cur;
cur = cur->next;
free(temp); // delete a duplicate node
}
}
prev->next = NULL; // NULL-terminate the modified list
return head;
}
I am trying to sort a singly linked list using bubble sort by manipulating ONLY the pointers, no keys.
The following gets stuck in the for loop and loops infinitely. I don't understand why this is. Can anybody explain to me why the end of the list is not being found?
Node* sort_list(Node* head)
{
Node * temp;
Node * curr;
for(bool didSwap = true; didSwap; ) {
didSwap = false;
for(curr = head; curr->next != NULL; curr = curr->next) {
if(curr->key > curr->next->key) {
temp = curr;
curr = curr->next;
curr->next = temp;
didSwap = true;
}
cout << curr->next->key << endl;
}
}
return head;
}
If I change the code so that the keys (data) are swapped, then the function works properly but for some reason I am not able make it work by manipulating only pointers.
Logical Error, you are creating an infinite loop with following code -
temp = curr;
curr = curr->next;
curr->next = temp;
I,e next_of_current is pointing to current, so curr->next will always be curr and never will be NULL;
Next you should use previous pointer to fix your list because your list can be traversed in a single direction. So, Think -
If A->B->C->NULL; and you make C and B swap then the new list will still point to A->B and next iteration will be wrong ... because you are not modifying your previous next.
So, another implementation may be -
Node* sort_list(Node* head) {
Node * curr;
Node * prev;
for(bool didSwap = true; didSwap; ) {
didSwap = false;
prev = head;
for(curr = head; curr->next != NULL; curr = curr->next) {
if(curr->key > curr->next->key) {
if (head == curr) {
head = curr->next;
curr->next = head->next;
head->next = curr;
prev = head;
} else {
prev->next = curr->next;
curr->next = prev->next->next;
prev->next->next = curr
}
didSwap = true;
} else if (head != curr) {
prev = prev->next;
}
//cout << curr->next->key << endl; // <- this may cause crash if curr->next now points to NULL; (i,e last element)
}
}
return head;
}
Hope this helps, regards.
You have following problem:
Let you have list with three members: ptr1->ptr2->ptr3. Before swap you have following pointer set: curr=ptr1; curr->next=ptr2; curr->next->next=ptr3. When you perform swap you receive curr=ptr2; curr->next=ptr1; curr->next->next=ptr2.
E.g. you lost ptr3. You need to change code of inner loop with following:
temp = curr;
temp->next = curr->next->next; // Save ptr3
curr = curr->next;
curr->next = temp;
didSwap = true;
The field you want to swap is the value. However, if you swap the node, the next field will change, the question becomes a little more complex, you need keep the next field right. In a word, change value is a simple and good method.
node *sorted_list(node *head) {
node *index1,*index2;
for(index1=head;index1->next!=NULL;index1=index1->next) {
for(index2=index1->next;index2!=NULL;index2=index2->next) {
if(index1->data>index2->data) {
int temp=index1->data;
index1->data=index2->data;
index2->data=temp;
}
}
}
return head;
}