I have a singly linked list. If I want to delete an known element from this linked list, what can I do?
For example:
Node* head; (44)
Node* tail; (39)
linked list: 44 27 59 13 45 39
we want to delete 45 from it. and get: 44 27 59 13 39
I only figured out that delete first element from list(if element(need to be removed) is first element of the list).
I got: head = head-> next;
How to remove intermediate node from list?
13 will be pointing 45 as its next element, simple change its next element to 39. And free the 45 from memory, just to keep memory clean from trash.
This pseudo code might help you :-
void remove(int key) {
Node* p = head->next;
Node*prev = head;
while(p!=NULL) {
if(p->data==key) {
prev->next = p->next;
free(p);
break;
}
prev = p;
p = p->next;
}
}
Look at the value in the next node, if there is a value. If that is the value you're looking for, then the next node is the one to delete, so you make the current node's next element point to the next node's next element, after preserving a pointer to the next node so that you can delete it.
// Assuming head is a non-const reference variable (or a global variable)
if (head == NULL)
return;
if (head->value == wanted)
{
head = head->next;
return;
}
for (Node *curr = head; curr->next != NULL; curr = curr->next)
{
if (curr->next->value == wanted)
{
Node *old = curr->next;
curr->next = curr->next->next;
delete old;
return;
}
}
return; // Possibly after reporting that the value wanted was not found
First, find the element you want to delete. Don't forget to handle when the element doesn't exist:
Node* find(Node* head, int value) {
do {
if (head->value == value) return head;
head = head->next;
} while (head);
return nullptr;
}
Then, you want to connect the previous node's next ptr to the next node. In a singly-linked list, you can track the previous node using a local variable. Don't forget to handle if the node you want to delete is the head (i.e. no previous node), or if the node is the tail (i.e. no next node):
Node *previous = nullptr;
do {
if (head->value == value) {
if (previous != nullptr) {
previous->next = head->next;
}
if (head == tail) {
tail = previous;
}
return;
}
previous = head;
head = head->next;
} while (head);
Think through the problem.
You need a loop to traverse all the nodes till you find the one you are looking for. Say you have Node* curr, prev both pointing to head.
while(curr != null)
For each node you need to check if the value matches or not with the node that you are looking for.
if (curr->value == node_you_are_looking_for->value)
If this is the matching node, delete this node. You have two pointers to update the links.
prev->next = curr->next;
prev = curr;
curr = curr->next;
prev->next = null;
delete(prev);
Else keep on traversing the list.
prev = curr;
curr= curr->next;
Then you can assemble all these steps and write a working program.
You just have to analyse the problem first and know the changes required if we delete a particular node.
let us suppose that we have the address of the node which is supposed to be deleted
there can be 3 cases if the node is the 1st node or the last node or a middle node ie a minimum 2 nodes.
void deletenode(struct node **s,struct node *t){
struct node *temp;
if(*s==t)
{
*s=t->next;
free(t);
}
else{
temp=*s;
while(temp->next!=t)
{
temp=temp->next;
}
temp->next=t->next;
delete(t);
}
}
Related
I need to write three separate functions for node deletion in a circular singly linked list (deleteFront(), deleteMiddle() and deleteEnd()). I have to use only tail (last). For some reason, my deleteEnd() function deletes second to the last node. Can anyone please help?
struct node
{
int data;
struct node* next;
};
// some other functions
// 6 -> 5 -> 4 -> 3 -> deleteEnd() does 6 -> 5 -> 3 ->
void deleteEnd(struct node* last)
{
if (last != NULL)
{
if (last->next == last)
last = NULL;
else
{
node* temp = NULL;
node* temp1 = last;
while (temp1->next != last)
{
temp = temp1;
temp1 = temp1->next;
}
temp->next = temp1->next;
delete temp1;
}
}
}
There are several issues with your deleteEnd function:
There is no way that the caller can get the new tail reference, because the tail argument is passed by value. The tail parameter should be a pass-by-reference parameter.
The statement after the loop (in the else block) does not remove the correct node. After the loop, temp1->next will be equal to last, and it should be that node that is removed, yet your code removes temp1. You can fix this by changing the loop condition and initialise the temp and temp1 variables to point to one node further in the list.
The else block does not update tail, yet it is clear that it should, since the original tail node is deleted.
Less of an issue, but in C++ you should not use NULL, but nullptr.
Here is a correction:
void deleteEnd(struct node* &last) // corrected
{
if (last != nullptr)
{
if (last->next == last)
last = nullptr;
else
{
node* temp = last; // corrected
node* temp1 = last->next; // corrected
while (temp1 != last) // corrected
{
temp = temp1;
temp1 = temp1->next;
}
last = temp; // added
temp->next = temp1->next;
delete temp1;
}
}
}
Try This
Explanation : So we are receiving head of the Circular Linked List and taking a curr pointer and pointing it to the head of the CLL.
Then we are taking another pointer and keeping it one step before the curr pointer so that we can point that pointer's next(prev->next) to curr's next(curr->next) and free the curr node.
void deleteTail(Node* &head)
{
Node* curr = head;
Node* prev = NULL;
while(curr->next != head)
{
prev = curr;
curr = curr->next;
}
prev->next = curr->next;
curr->next = NULL;
delete curr;
I'm trying to delete every node at positions divisible by 5. With my approach I cannot seem to delete the last node:
void removeDivFive(Node* head){
int count = 0;
Node* temp = head;
while(temp != NULL){
count++;
if(count%5==0){
if(temp->next != NULL){
temp->value = temp->next->value;
temp->next = temp->next->next;
}
}
temp = temp->next;
}
while(head != NULL){
cout<<head->value;
head = head->next;
}
}
What I'm doing is copying the value of the next node to the current one and changing the pointer to the next next node. By doing this I cannot delete the last node if the list has 10 nodes.
Any help would be appreciated
First off, you are leaking the nodes you "remove". You need to actually destroy them since they are no longer being used.
Now, regarding your actual problem - what do you thing temp->next points at when the last node in the list is at a position divisible by 5? NOTHING! Thus, if (temp->next != NULL) evaluates as false, so you aren't even attempting to do anything with that last node, you just skip past it, which is why you are not removing it.
For every 5th node, you are copying the value of the next node into the current node, and then pointing the current node to skip the next node. In other words, you are not removing the 5th, 10th, 15th, etc nodes at all. You are actually removing the 6th, 11th, 16th, etc nodes instead. You need to remove the current node instead of the next node.
Which also means, you need to keep track of the previous node in the list so that you can re-link its next pointer to point at the next node that follows the current node being removed.
Try something more like this instead:
void removeDivFive(Node* head){
int count = 0;
Node *temp = head, *prev = NULL, *next;
while (temp != NULL){
++count;
next = temp->next;
if ((count % 5) == 0){
if (prev != NULL) {
prev->next = next;
}
delete temp;
}
else {
prev = temp;
}
temp = next;
}
}
Online Demo
Alternatively (as described by #GoswinvonBrederlow in comments):
void removeDivFive(Node* head){
int count = 0;
Node *temp = head, *next;
while (temp != NULL){
++count;
if ((count %4) == 0){
if (temp->next != NULL){
next = temp->next->next;
delete temp->next;
temp->next = next;
}
}
temp = temp->next;
}
}
Online Demo
As mentioned in the comments the deleted node isn't counted. So you need to delete a node every 4 counts instead of every 5. And if you use count%4 == 0 then the first time temp will point at node 4 and you want to delete the 5th node. So no need for temp->value = temp->next->value;, just remove the next node. Then next time around when count = 8 then temp will point at node 9. So again temp->next is the node to remove. ...
So the condition always fires for the node before the 5th, which is perfect for removing it.
void removeDivFive(Node* head){
int count = 0;
for (Node* temp = head; temp != NULL; temp = temp->next) {
count++;
if(count%4==0){
if(temp->next != NULL){
Node *t = temp->next;
temp->next = t->next;
delete t;
}
}
}
while(head != NULL){
cout<<head->value;
head = head->next;
}
}
In place of *head_ref = temp->next;, why can't I assign it as *head_ref = *head_ref->next?
Why should I use temp? Aren't they pointing to the same place?
class Node{
public:
int data;
Node* next;
};
void deleteNode(Node** head_ref, int key){
Node* temp = *head_ref;
Node* prev = NULL;
if(temp!=NULL && temp->data==key){
*head_ref = temp->next;
delete temp;
return;
}
else{
while(temp!=NULL && *head_ref->data!=key){
prev = temp;
temp = temp->next;
}
}
Your code does not compile, *head_ref->data should be (*head_ref)->data.
The reason why you should use temp is that you want to modify *head_ref only if the element you want to delete is the head element. If you delete any other element of the list, the head pointer must stay the same.
But your code is wrong anyway. You're doing things in the wrong order. You must first find the element you want to delete, and then handle the deletion.
Your code handles the deletion first and then finds the element to delete which is absurd.
You want this:
void deleteNode(Node** head_ref, int key) {
Node* current = *head_ref;
Node* previous = NULL;
// find element to delete
while (current && current->data != key)
{
previous = current;
current = current->next;
}
// if current is NULL here then the element has not been found
if (current != NULL)
{
// element found,
// current points to element found
// previous points to previous element or NULL if current is head
if (previous == NULL)
{
// deleting head element -> we need to update head_ref
*head_ref = current->next;
}
else
{
// deleting any other element -> update next pointer of previous element
previous->next = current->next;
}
delete current;
}
}
That being said, this is rather C code than C++ code. You should use standard containers rather than making your own, or at least use C++ idioms such as constructors.
would help me to solve this problem
i am trying to insert the node at ith location in linked list using recursion
here is the code please help me to imporve the code
i ma specifically facing problem at the end when i have to return the head i am not getting how to return
Node* insertNodeRecursively(Node*head, int n, int data)
{
if(head == nullptr)
{
return head;
}
else if(n==0)
{
Node* newNode= new Node(data);
newNode->next = head->next;
head->next = newNode;
return head;
}
Node * x = insertNodeRecursively(head->next,n-1,data);
}
So I guess you want the function insertNodeRecursively to return the new head, right? Anything else would not work without considering the special case of inserting at position 0 in the caller function.
You could do the following:
if (n == 0) {
Node *newNode = new Node(data);
newNode->next = head;
return newNode;
}
if (head == nullptr) {
return nullptr;
}
Node *node = insertNodeRecursively(head->next, n - 1, data);
head->next = node;
return head;
The idea is that when this is not the position to insert to, we need to assume the next recursive call might give us a new head (from that position on), so we need that head->next = node; assignment. To call the node passed as first argument head might confuse as it is not always the head of the list (Only at the start of the recursion)! It is rather the node in front of which you want to insert in case n is 0. The problem with what you wrote in the n == 0 case is that you always return the old head, even though you should return newNode. The head node should be what follows after newNode.
I have to write a method that's going to delete the last node from the List. Do you guys have any ideas on how I should approach this?
If you have a single-linked list, you have no choice but to iterate through the entire list to the last node, maintaining a pointer to the previous node so you can reset its next field when freeing the last node:
if (head)
{
node *curNode = head;
node *prevNode = NULL;
while (curNode->next)
{
prevNode = curNode;
curNode = curNode->next;
}
if (prevNode) prevNode->next = NULL;
delete curNode;
}
If you were using a double-linked list instead, this would be easier, as you can keep a pointer to the last node in the list and just operate on it directly:
if (head == tail)
{
delete head;
head = tail = NULL;
}
else if (tail)
{
node *curNode = tail;
tail = curNode->previous;
tail->next = NULL;
delete curNode;
}
Of course, if you are really using C++ then you should be using the STL's std::list (double-linked) or std::forward_list (single-linked) containers instead, which handle these details for you.
To delete the last element on a list all you need to do is maintain two separate nodes. Initially one should point to the head of the list and the other should point to the second element on the list. You should do something like the following :
if(head == NULL)
return 0;
else if(head->next == NULL){
Node *temp = head;
delete temp;
head = NULL;
}
else{
Node *one = head;
Node *two = head->next;
while(two->next != NULL){
two = two->next;
one = one->next;
}
one->next = NULL;
delete two;
}