Delete nodes at positions divisible by 5 in linked list - c++

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;
}
}

Related

How to delete "end" node from a circular linked list using only tail in c++?

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;

Insertion in Singly Linked List running on infinite loop

Linked List PrintNode function is running on an infinite loop.
class Node{
public:
int data;
Node* next;
};
Node * head; //first variable of inked list
void Insert(int x){
//insertion at beginning
Node* p = new Node;
p->data = x;
p->next = NULL; //when list is empty
//two scenarios to insert node
//one when linked list is empty
if (head == NULL){
head = p; //head becomes the first node
}
//if linked list is not empty
if (head != NULL){
p->next = head;
head = p; //pointing head at the newly created node
}
}
void PrintNode(Node* head){
for ( Node * temp = head; temp != nullptr; temp = temp->next )
{
cout << temp->data << "->";
}
}
int main (){
head = NULL; //points nowhere
int n;int x;
cin >> n;
for(int i = 0 ; i < n ;i ++){
cout << "Enter element" << endl;
cin >> x;
Insert(x);
}
PrintNode(head);
}
I expect the output to be list printed as for example: 1->2->3-> but,
running on an infinite loop.
The first Node you add ends up pointing at itself. Take a look at this chunk of code from Insert
if (head == NULL){
head = p; //head becomes the first node
}
//if linked list is not empty
if (head != NULL){
p->next = head;
head = p; //pointing head at the newly created node
}
You'll point head at your new Node, then enter the next if since head isn't NULL. If you replace the second if with an else, you should be fine.
Look carefully at this code:
if (head == NULL){
head = p; //head becomes the first node
}
//if linked list is not empty
if (head != NULL){
p->next = head;
head = p; //pointing head at the newly created node
}
When head is NULL both branches of code get run resulting in your head node pointing to itself. The correct code would be:
if (head == nullptr){
head = p; //head becomes the first node
}
//if linked list is not empty
else{
p->next = head;
head = p; //pointing head at the newly created node
}
When you update the head pointer as you insert your first element, both if statements will be executed and the head pointer will never be empty in the second if statement, so it should be if then else, like below
if (head == NULL){
head = p; //head becomes the first node
}
//if linked list is not empty
else if (head != NULL){
p->next = head;
head = p; //pointing head at the newly created node
}

Deletion in a linked list

Qn) Given only a pointer to a node to be deleted in a singly linked list, how do
you delete it?
I am trying to delete the last element i.e., 1 but the else part goes into an infinite
loop printing garbage values.
Original link.
int main()
{
struct Node* head = NULL;
push(&head, 1);
push(&head, 4);
push(&head, 6);
push(&head, 8);
print(head);
del_p(head->next->next->next);
cout << endl;
print(head);
return 0;
}
void del_p(struct Node* current)
{
struct Node* temp;
if (current->next != NULL)
{
temp = current->next;
current->data = temp->data;
current->next = temp->next;
free(temp);
}
else
{
free(current);
current = NULL;
}
}
The else branch of your function tries to reassign current to NULL. This is problematic because current is a local copy of the pointer passed in. That is, you can't modify the value of the original pointer.
This is why you are receiving garbage, because you're accessing a node whose memory has already been deallocated.
You either need a double pointer, or preferably a reference to the node:
void del_p(struct Node*& current)
If you pass in the node to be deleted and the head node then you can loop until you find the node prior to the node to be deleted. You then need to point the prior node to the node that is pointed to by the node to be deleted and then you can free the node you want to delete.
void delete(struct Node* to_delete, struct Node* head)
{
// check if node to be deleted is the head
if (to_delete == head)
{
head = to_delete->next;
return;
}
// make a local copy of the head just in case as to not alter it
struct Node* tempHead = head;
while(tempHead->next != to_delete)
{
tempHead = tempHead->next;
}
tempHead->next = to_delete->next;
free(to_delete);
}
Just as a disclaimer I haven't tested this code, but conceptually it should work.
The typical algorithm for deleting a node on a linked list would follow the next steps:
Get a temp pointer started in Head.
Move your temp to the node you want to delete (in this case one before the last: temp->next == NULL).
Free the memory for temp2.
Set the pointer of temp->next to NULL.
Return the pointer to head.
Now this is not the only algorithm, there are a lot of ways you can accomplish this. The following code would be my solution to the function del_p (if you would want to delete the last node):
void del_p(struct Node *head)
{
if (head != NULL)
{
struct Node *temp = head;
while (temp->next != NULL) temp = temp->next;
free(temp);
}
}
You can make this code a little more general to make it possible to delete any Node, by passing a pointer to that node (or a value), the code would look as follows:
void del_p(struct Node **head, struct Node *delete_node)
{
if (head != NULL)
{
struct Node *temp = *head;
if (temp == delete_node)
{
*head = (*head)->next;
free(temp);
}
else
{
while (temp->next != NULL && temp->next != delete_node)
temp = temp->next;
if (temp->next != NULL && delete_node != NULL)
{
temp->next = delete_node->next;
free(delete_node);
}
}
}
}
Hope this works for you, this code isn't tested, but tell me if you have troubles!

How to remove intermediate node from a linked list

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);
}
}

How do I delete a node from linked list?

How can I delete a node (between two nodes) from a single linked list without passing any parameters to the class function?
For example, I have a list of 6 nodes with one head node and I want to delete two of them (without prior knowledge of their address or position) from a class function, how would I do that?
void WordList::deleteNode(){
Node *temp;
temp=head;
if(temp->count<=10)
{
//delete this node... not sure how though
}
else
temp=temp->next;
}
where WordList is my class, Node is my struct which holds a word, a count, and a pointer.
I want to delete any node that has a counter of 10 or less.
Your edit has prior information, the bit that states "counter <= 10" :-)
Pseudo-code for deleting elements meeting that criteria in a singly-linked list:
def delLessThanTen:
# Delete heads meeting criteria, stop when list empty.
while head != NULL and head->count <= 10:
temp = head->next
free head
head = temp
if head == NULL:
return
# Head exists, with count > 10, process starting there (we check
# NEXT element for criteria then delete if met).
ptr = head
while ptr->next != NULL:
# If next in list meets criteria, delete it, otherwise advance.
if ptr->next->count <= 10:
temp = ptr->next->next
free ptr->next
ptr->next = temp
else:
ptr = ptr->next
return
I find the question too confusing.
Deletion of a node from the list is always based on some criteria e.g. the content of the element, the position of the element etc (unless you are deleting all the elements in the list)
something like this:
void WordList::deleteNode(){
Node *prev=NULL;
temp=head;
bool done=false;
while (!done)
{
if (temp->count<=10)
{
if (prev == NULL)
{
head = temp->next;
} else
{
prev->next = temp->next;
}
// delete data in temp, and the node if necessary
temp = temp->next;
done = (temp==NULL) || // some other condition, like deleted 2
} else
{
prev=temp;
temp = temp->next;
done = (temp==NULL);
}
}
Have a previous variable initialized to null. If you delete a node, change previous's next to the element's next, unless previous is null (you are at the start of the list) when you leave previous null and change root to the deleted element's next. If you don't delete the element, change previous to the element.
Here previous will always point to the previous element or be null if you're at the start of the list.
void WordList::deleteNode() {
Node *temp = head;
Node *previous = null;
while (temp != null) {
if(temp->count <= 10) {
// delete node
if (previous == null) {
// there is no previous node, so point head of list past the current node
head = temp->next;
} else {
// there is a previous node, so just point it past the current node
previous->next = temp->next;
}
} else {
// not deleting, so set previous to temp
previous = temp;
}
temp = temp->next;
}
}