Delete the last node of a linked list - c++

I am trying to delete the last Node of a linked list,
I have the first element of the list. But the function does not work I would be happy if you could help me
Code -
void deleteNode(Node* firstNode)
{
Node* currNode = firstNode;
while (currNode->next != NULL)
{
currNode = currNode->next;
}
delete currNode->next;
currNode->next = NULL;
}

You are deleting the one after the last node, which should be NULL anyways.
void deleteNode(Node* firstNode)
{
//first check if firstNode is NULL or last node.
if(firstNode == NULL)
return;
if(firstNode->next == NULL)
{
delete firstNode;
firstNode = NULL;
return;
}
Node* currNode = firstNode;
while (currNode->next && currNode->next->next != NULL)
{
currNode = currNode->next;
}
delete currNode->next;
currNode->next = NULL;
}

You need to consider a few things:
Any operation that could potentially affect the head pointer must provide a mechanism for returning the updated head pointer (an in/out param i.e. pointer to pointer or reference-of-pointer, or by function return result; I prefer the former).
Any pointer holding the address of the last node in the list, be it the head pointer or any other, must be set to NULL.
That said,
Pointer To Pointer
void deleteLastNode(Node** firstNode)
{
while (*firstNode && (*firstNode)->next)
firstNode = &(*firstNode)->next;
free(*firstNode); /**/
*firstNode = NULL; /**/
}
Note if the pointer passed in by-address is already NULL, both lines above marked with /**/ need not be executed, but are harmless none-the-less, as free()-ing NULL is supported per the standard as a no-op.
Called by passing the address of the head pointer, the content of which must be NULL if the list is empty.
Node *head = NULL;
//... code to populate the list.
deleteLastNode(&head);
Reference of Pointer
With C++, you can also pass the head pointer by reference, for example:
void deleteLastNode(Node*& head)
{
Node **firstNode = &head;
while (*firstNode && (*firstNode)->next)
firstNode = &(*firstNode)->next;
free(*firstNode); /**/
*firstNode = NULL; /**/
}
Invoked as:
Node *head = NULL;
//... code to populate the list.
deleteLastNode(head);
Which mechanism you choose is up to you.

You are deleting one after the final node.
delete currNode;

Try this:
void deleteNode(Node *firstNode)
{
Node* currNode = firstNode;
Node* nextNode = firstNode->next;
while(nextNode != NULL)
{
currNode = nextNode;
nextNode = nextNode->next;
}
delete currNode;
}

The problem with your code is, at the last instance curNode points to the last node of the list. When you delete the curNode, you will no longer be left with node, ie, the data and next part. So you now you cannot access next part of curNode. This code will lead to runtime error:
currNode->next = NULL;
Instead try this:
If the list contains only one element, then firstNode points to NULL and the only node is deleted. If there are more than two items in your list, your have to iterate to the last second element, set its next value to NULL, and delete the last node with the help of a temp pointer.
void pop_back(struct node** firstNode)
{
struct node* p = *firstNode;
if(p == NULL)
cout << "List empty." << endl;
else if(p->next == NULL){
cout << "Element " << p-> data << " deleted." << endl;
delete *firstNode;
*firstNode = NULL;
}
else
{
while(p->next->next != NULL){
p= p->next;
}
struct node* temp = p-> next;
p->next = NULL;
cout << "Element " << temp->data << " deleted." << endl;
delete temp;
}
}

void delBottom()
{
clrscr();
Node *nb=H; //current
Node *nn=(H->getNext()); //next
if(NULL==H)
{
cout<<"List Empty";
}
else if(H==T)
{
delete H; //H-Head
H=T=NULL;
}
else
{
while(NULL!=(nn->getNext()))
{
nb=nn;
nn=nn->getNext();
}
delete nn;
nb->setNext(NULL);
T=nb; //T-Tail
}
}

actually, you should write like this:
void deleteNode(Node* firstNode)
{
Node* currNode = firstNode;
while (currNode->next != NULL)
{
currNode = currNode->next;
}
***delete currNode;
currNode = NULL;***
}
cause, currNode is the last node.

Related

how to delete current linked list node without tracking previous node

I was wondering if it's possible to delete a node by value in a linked list in C++ without tracking both 'previous' and 'current' nodes.
What I did is copy next node's information into current node, link current node to next next node, and delete next node.
I've attempted something like below. However, this only works if the node to delete is not the last node. I'm unable to figure out how to accommodate for the last node.
struct Node
{
int data;
Node* next;
};
void LinkedList::deleteNode(int item)
{
Node* tmpNode = m_head;
while (tmpNode != nullptr)
{
if (tmpNode->data == item)
{
if (tmpNode->next != nullptr) // not last node
{
// this works
Node* delNode = tmpNode->next;
tmpNode->data = tmpNode->next->data;
tmpNode->next = tmpNode->next->next;
delete delNode;
}
else // last node
{
// this does not work
delete tmpNode;
tmpNode = nullptr;
}
std::cout << "deleted item " << item << '\n';
return;
}
tmpNode = tmpNode->next;
}
std::cout << "delete failed: item " << item << " not found\n";
}
When you delete a node, you have to set the next of the previous node to nullptr. Otherwise, it will stay pointing to a deleted node.
Suggestion:
At the beginning of the function, create:
Node* previousTmpNode = nullptr;
Store the address of the previous node when you scan the linked list:
Node* previousTmpNode = tmpNode ; //call right before tmpNode = tmpNode->next;
And then call:
previousTmpNode->next = nullptr; //call right after you deleted the last element.
Or, change your nodes so they point backwards (double linked-list).
As this is probably an exercise/home-work, I'll answer in a sudo(untested) manor. And it will just work for the last node.
Node* prev = nullptr;
for(auto track = m_head; track; track = track->next){
if(track->data != item)
continue;
if(!prev){
m_head = track->next;
delete track;
break;
}
prev->next = track->next;
delete track;
break;
}

Unable to create or return Reversed Linked list

Here using the function returnReverseLinkedList I am returning the reversed linked list of the given linked list. But the problem with this approach is that i lose the original linked list. So I make another fucntion called createReversedLinkedList to make a copy of the original linked list and reverse the copy and maintain possession of both.
unfortunately createReversedLinkedList is giving Runtime error.
obviously my end goal is to check if the given linked list is palindrome or not. This issue is just a stepping stone.
Could someone tell me why?
//Check if a linked list is a palindrome
#include <iostream>
using namespace std;
class node
{
public:
int data;
node *next;
node(int data)
{
this->data = data;
this->next = NULL;
}
};
node *returnReverseLinkedList(node *head)
{
// Will Lose original Linked List
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return head;
node *prev = NULL;
node *curr = head;
node *tempNext = head->next;
while (tempNext != NULL)
{
curr->next = prev;
prev = curr;
curr = tempNext;
tempNext = tempNext->next;
}
curr->next = prev;
return curr;
}
node *createReversedLinkedList(node *head)
{
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return NULL;
else
{
node *temp = head;
node *newHead = NULL;
node *newTail = NULL;
while (temp != NULL)
{
node *newNode = new node(temp->data);
if (newHead == NULL)
{
newHead = newNode;
newTail = newNode;
}
else
{
newTail->next = newNode;
newTail = newNode;
}
}
return returnReverseLinkedList(newHead);
}
}
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head);
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false;
cout << "debug 2" << endl;
original = original->next;
reverse = reverse->next;
}
return true;
}
// #include "solution.h"
node *takeinput()
{
int data;
cin >> data;
node *head = NULL, *tail = NULL;
while (data != -1)
{
node *newnode = new node(data);
if (head == NULL)
{
head = newnode;
tail = newnode;
}
else
{
tail->next = newnode;
tail = newnode;
}
cin >> data;
}
return head;
}
void print(node *head)
{
node *temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
int main()
{
node *head = takeinput();
node *revese2 = createReversedLinkedList(head);
print(revese2);
// bool ans = check_palindrome(head);
// if (ans)
// cout << "true";
// else
// cout << "false";
// return 0;
}
As asked by the OP, building a reversed linked is simply done by building as you would a stack (e.g LIFO) rather than duplicating the same original forward chain. For example:
node *createReversedLinkedList(const node *head)
{
node *newHead = NULL;
for (; head; head = head->next)
{
node *p = new node(head->data)
p->next = newHead;
newHead = p;
}
return newHead;
}
Note we're not hanging our copied nodes on the tail of the new list; they're hanging on the head of the new list, and becoming the new head with each addition. That's it. There is no need to craft an identical list, then reverse it; you can reverse it while building the copy to begin with.
A note on the remainder of your code. You have a dreadful memory leak, even if you fix the reversal generation as I've shown above. In your check_palindrome function, you never free the dynamic reversed copy (and in fact, you can't because you discard the original pointer referring to its head after the first traversal:
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head); // only reference to reversed copy
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false; // completely leaked entire reversed copy
original = original->next;
reverse = reverse->next; // lost original list head
}
return true;
}
The most obvious method for combating that dreadful leak is to remember the original list and use a different pointer to iterate, and don't leave the function until the copy is freed.
bool check_palindrome(const node *head)
{
bool result = true;
node *reverse = returnReverseLinkedList(head);
for (node *p = reverse; p; p = p->next, head = head->next)
{
if (p->data != head->data)
{
result = false;
break;
}
}
while (reverse)
{
node *tmp = reverse;
reverse = reverse->next;
delete tmp;
}
return result;
}

Implementing "deleting algorithm" for linked list type data structures

Here is a delete function I have written to delete some nodes from my linked list when needed.
the linked list is stored as alphabetically ordered
Using below function, when I try to delete the very first element of a linked list (named head), I get an runtime error when I am trying to print the linked list (using the print function) and the program crashes. I am aware that this is probably caused by not creating a new head node. But I do not know how to solve this. This is probably very simple but couldn't figure out. Can you please help :)
this is the delete function:
void deleteName(someStruct * &head, string name)
{
someStruct * ptr = head;
someStruct * previous;
if(head == NULL)
{
cout << "empty";
}
else if(head->name == name)
{
ptr = head;
head = head->next;
delete head;
}
else
{
while (ptr -> name != name)
{
previous = ptr;
ptr = ptr->next;
}
previous->next = ptr->next;
delete ptr;
}
}
this is the print function:
void Print(someStruct * head)
{
someStruct * pointer = head;
//List is empty
if(head == NULL)
{
cout << "List is empty" << endl;
}
else
{
while(pointer != NULL)
{
cout << pointer->name;
cout << pointer->points << endl;
pointer = pointer->next;
}
}
}
else if(head->name == name)
{
ptr = head;
head = head->next;
delete head;
}
This:
saves the old value of head to ptr, which is correct
advances the inout param head, which is also correct
completely ignores ptr, which contains the old node you want to delete, and instead deletes the current list head, leaving the inout param head pointing to a deleted node.
This bit isn't correct.
Just change delete head to delete ptr.
Note for future reference: the good way to structure this is to use a local sentinel node which doesn't need to be deleted. This removes your special case for head (by adding the invariant that your temporary head can never be removed) and simplifies the code.
void deleteName(someStruct * &head, string name)
{
if(!head) {
cout << "empty";
return;
}
someStruct tmphead;
tmphead.next = head;
for (someStruct *prev = &tmphead; prev->next; prev = prev->next) {
if (prev->next->name == name) {
auto todelete = prev->next;
prev->next = todelete->next;
delete todelete;
// if there can be only one match, just bail out
break;
// otherwise, if there can be many, go round again
// but remember to check whether prev->next is null
// if (!prev->next) break;
}
}
head = tmphead.next;
}
If your someStruct is too large or complex to use a temporary head like this, you can do the same with a temporary local head pointer, and make prev a pointer-to-pointer.
The delete head in else if block is the problem.
Change the block to this :
else if(head->name == name) {
//ptr = head; You don't have to. You already have initialized ptr with head
head = head->next;
delete ptr; //Delete prt not head, head is now the next node which you assigned in previous line
}
else if(head->name == name){
ptr = head;
head = head -> next;
delete ptr; // change to this statement n you're good to go
}

insert at end of linked list

I am writing a simple function to insert at the end of a linked list on C++, but finally it only shows the first data. I can't figure what's wrong. This is the function:
node* Insert(node* head, int data)
{
if (head == NULL) {
head = new node();
head->data = data;
head->link = NULL;
return head;
}
else {
node* temp = head;
while (temp != NULL) {
temp = temp->link;
}
node* temp2 = new node();
temp2->data = data;
temp2->link = NULL;
(temp->link) = temp2;
return head;
}
}
Change the condition in while construct from:
while (temp!=NULL) {
temp=temp->link;
}
To
while (temp->link!=NULL) {
temp=temp->link;
}
In statement, temp->link = temp2, temp is a null pointer. You were dereferencing a NULL pointer.
To append a node at the back, temp pointer should point to the last node of the linked list. So, in the while loop, you need to just stop linked list traversal when you have reached the last node, i.e, the node whose link member points to nothing (has NULL). while (temp->link!=NULL) will stop at the last node as last node will have link member pointing to NULL.
You can simplify your logic by doing this:
void Insert(node **pnode, int data)
{
while (*pnode) {
pnode = &(*pnode)->link;
}
*pnode = new node(data, NULL);
}
assuming you have a node constructor that initializes data and link from arguments.
Instead of calling it as
head = Insert(head, 42);
you'd now do
Insert(&head, 42);
change while(temp!=NULL) to while(temp->link!=NULL)
node* Insert(node* head, int data)
{
if (head == NULL) {
head = new node();
}
else {
while (head->link != NULL) {
head = head->link;
}
head = head->link = new node();
}
head->data = data;
head->link = NULL;
return head;
}

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!