Deletion of node at end of linked list C++ - c++

Hope you had a nice day/night so far, I'm trying to implement a stack using linked list, and I pretty much know how to insert an item at the end of the list. I'm trying to delete a node at the end of the list, but I can't do it properly.
void Pop(){
Node* temp1 = head;
Node* temp2 = NULL;
while(temp1 != NULL){
temp2 = temp1;
temp1 = temp1->next;
}
delete temp1;
temp2->next = NULL;
}
That was my code to delete the node at the end of the list. I played around with a lot but this didn't make the program stop executing or print out numbers infinitely.
So I "pushed" 3 numbers and printed them in between each "push" and "popped" twice and printed the results in between as well. But the output is like this:
1
1 2
1 2 3
1 2 3
1 2 3
What I would want to happen is this:
1
1 2
1 2 3
1 2
1
Thanks in advance!:D

Your loop spins until temp1 becomes NULL, and then you are trying to delete it. So you are actually deleting... nothing.
Check if temp1 is not NULL
Check if temp1->next is not NULL
Check if temp2 is not NULL
Set head to NULL if temp1 == head
void Pop(void) {
Node *t = head, *p = NULL;
if (t == NULL) {
return;
}
while (t->next != NULL) {
p = t;
t = t->next;
}
delete t;
if (p != NULL) {
p->next = NULL;
} else {
head = NULL;
}
}

By the time temp1 is null, it means you've hit the end of the list. You'll need to stop when the check for temp1.next is null.
if (!head)
return; // or throw ... no element to pop
while(temp1->next){
temp2 = temp1;
temp1 = temp1->next;
}
if (temp2) // If the element had a single element, we've just popped head.
temp2->next = NULL;
else
head = null;
delete temp1;
As an aside, you'll want to add robustness to guard against a list with a null head or a single element.

The other answers already correctly point out the bug in your code (the loop doesn't terminate early enough). I just wanted to mention that you could avoid the need for any tempN pointer variables by using pointers-to-pointers. I.e. instead of pointing to the nodes, you point to the references to nodes:
void pop( Node **n ) {
if ( !*n ) {
return;
}
while ( (*n)->next ) {
n = &(*n)->next;
}
delete *n;
*n = 0;
}

Related

Delete nodes at positions divisible by 5 in linked list

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

How do you delete all the nodes on the right of a linked list when a value greater than 'x' is encountered?

I don't see solution to this specific question on stackoverflow. So I'm posting this.
My requirement is to delete all the nodes on the right of a linked list when a value greater than 'x' is encountered?
For Ex.
Sample Input:
Linked list has values: 5 1 2 6 and x = 5
Output: 5 1 2
Sample Input
Linked list has values: 7 1 2 6 and x = 6
Output: null (since 7 is greater than 6, it should delete all the nodes on the right)
Sample Input:
Linked list has values: 5 4 7 6 and x = 6
Output: 5 4
I came up with this solution, but I'm trying to find an optimal solution
//head is the root node, nodes greater that "value" should be deleted
Node Delete(Node head, int value) {
// Complete this method
Node cur = head;
Node prev = null;
if(cur == null)
return head;
if(cur != null && cur.data > value )
{
while(cur != null)
{
prev = cur;
cur = cur.next;
}
prev.next = cur;
head = prev;
return head;
}
else
{
while(cur != null && cur.data <= value)
{
prev = cur;
cur = cur.next;
}
if(cur != null && cur.data > value)
{
while(cur != null)
{
cur = cur.next;
}
prev.next = cur;
return head;
}
prev.next = null;
return head;
}
}
Here is a simple O(n) solution in Javascript-style pseudocode,
with several identifiers renamed for clarity.
function deleteGreater(head, value) {
if (head == null) return null;
if (head.data > value) {
deallocate(head); //discard the entire list
return null;
}
var current = head;
while (true) {
if (current.next == null) return head; //end of list
if (current.next.data > value) break;
current = current.next;
}
deallocate(current.next); //discard the rest of the list
current.next = null;
return head;
}
I trust you can convert it to any language you want.
For languages with garbage collection, you can remove the deallocate() calls.
For languages without garbage collection, override the object's deallocation method to make sure that it also deallocates the next property.
In language like Java which have garbage collection, it is as simple as to set the next of last element to null which in worst case will be of O(n) (which will happen when matched with last element)
Node deleteGreaterThan(Node head, int value){
if(head==null || head.data>value)return null;//if head is itself greater than value
Node temp = head;
while(temp.next != null && temp.next.data<=value){
temp= temp.next;
}
temp.next = null;
return head;
}
head = deleteGreaterThan(head, 5);
I guess in language like c, you might have to explicitly delete each element and free the memory, no experience with c, so can't say much, even in that case it will only be O(n)
Like #100rabh said, in a language without garage collection you need to free every single node you allocated. Here is an example in C of how to do that. Notice that calling Delete is still O(n) because we actually update the previous node's next pointer while freeing the current node.
#include <malloc.h>
#include <stdio.h>
struct _Node {
struct _Node *next;
int data;
};
typedef struct _Node Node;
Node* Build(int value)
{
int i;
Node *ptr, *head=NULL;
for (i=1; i<value; i++)
{
if(head==NULL)
{
head=malloc(sizeof(Node));
ptr=head;
}
else
{
ptr->next=malloc(sizeof(Node));
ptr=ptr->next;
}
ptr->data=i;
ptr->next=NULL;
printf("Build: node=%p {data=%d next=%p}\n", ptr, ptr->data, ptr->next);
}
return head;
}
void Print(Node *head)
{
Node *ptr=head;
while(ptr!=NULL)
{
printf("Print: node=%p {data=%d, next=%p}\n", ptr, ptr->data, ptr->next);
ptr=ptr->next;
}
}
/*
* We can't pass head or ptr->next directly
* Because then we can't update it's value when we free what it points to
* So we pass the pointer to head or ptr->next instead
* Here we actually update head or ptr->next to point to the next node until we are finished
*/
void Free(Node **ptr)
{
Node *temp;
if(ptr==NULL) return;
while(*ptr!=NULL)
{
temp=*ptr;
*ptr=(*ptr)->next;
printf("Free: node=%p {data=%d next=%p}\n",temp,temp->data,temp->next);
temp->data=-temp->data;
temp->next=NULL;
free(temp);
}
}
/*
* We can't pass head or ptr->next directly
* Because then we can't update it's value when we free what it points to
* So we pass the pointer to head or ptr->next instead
* Nothing gets updated in this function - Free does all the updating
*/
void Delete(Node **ptr, int value)
{
if(ptr==NULL) return;
while(*ptr!=NULL)
{
if((*ptr)->data>value)
{
printf("Delete: node=%p {data=%d node=%p}\n",*ptr,(*ptr)->data,(*ptr)->next);
Free(ptr);
return;
}
ptr=&(*ptr)->next;
}
}
int main(void)
{
Node *head=Build(10);
Print(head);
Delete(&head, 5);
Print(head);
Free(&head);
return 0;
}

What's wrong with the insert at the end operation in this Linked List?

I have written this code for implementing Linked List in c++. It worked perfectly till i added the insert at end function to it. Please see what's wrong! Without the insertatend function, output is correct. After adding that function, the output is 1 10 which is actually the insert at start and end's outputs.
void List::insertatend(int num)
{
Node *new_node=new Node(num);
if(listptr==NULL)
listptr=new_node;
else
for(Node *temp=listptr; temp->next!=NULL; temp=temp->next)
temp->next=new_node;
}
The problem is in the lines:
for(Node *temp=listptr; temp->next!=NULL; temp=temp->next)
temp->next=new_node;
It seems like you haven't walked through the logic of how the code works.
You will first need to iterate until temp->next is NULL and then use
temp->next=new_node;
The code to implement that logic is:
Node* temp = listptr;
for ( ; temp->next != NULL; temp = temp->next )
{
// Do nothing in the loop.
}
temp->next = new_node;
Here's the updated function:
void List::insertatend(int num)
{
Node* new_node = new Node(num);
if( listptr == NULL)
{
listptr = new_node;
}
else
{
Node* temp = listptr;
for ( ; temp->next != NULL; temp = temp->next )
{
}
temp->next = new_node;
}
}
Go through the basic logic of how to add the every new node at end of previous node.Bug is in below two lines of insertatend function, explanation I mentioned in comments.
for(Node *temp=listptr; temp->next!=NULL; temp=temp->next) //it should be dummy loop
temp->next=new_node;//In all old nodes next part will replace by new_node which is wrong
Modiy Insert_end() function as
void List::insertatend(int num)
{
Node *new_node=new Node(num);
if(listptr==NULL)
listptr=new_node;
else{
Node *temp=listptr;
for( temp ; temp->next!=NULL ; temp=temp->next); /** rotate dummy loop until temp is not reaching to last node **/
temp->next = new_node;// in last node next put the new node address
new_node->next = 0; // and new node nnext put the zero
}
}

C++: Pointers pointing to freed memory space

The two lines of code at the bottom tail = head;
tail->next= NULL; causes the program to crash, when I call the extractMin() function. If i comment them out, everything is happening as supposed. Is this happening cause they are pointing to addresses in memory that has been freed?
The only clue the compiler gives me is this:EXC_BAD_ACCESS (code=2, address=0x0). I notice immediately the address being 0x0 so there is a problem there, but what exactly?
string LinkedListPQueue::extractMin() {
if (isEmpty())
error("Tried to dequeue from epmpty queue!");
cell *toBeDeleted = head; //pointer to this head
string value = head->value; //get value of this head
head = head->next; //move so this head is not the same as the one to be deleted
delete toBeDeleted; //delete previous head.
return value;
}
/* Implementation notes: enqueue
* -----------------------------
* We have to search to find the proper position, which can be a bit tricky with
* a singly-linked list. We walk two parallel pointers, one a step behind the other,
* until we find the correct position to insert the new cell, which we then splice
* into place. Note the special case of inserting at the head. Alternatively, this
* operation could work recursively.
*/
void LinkedListPQueue::enqueue(const string& elem) {
cell *cur, *prev, *newOne = new cell;
newOne->value = elem;
for (prev = NULL, cur = head; cur != NULL; prev=cur, cur = cur->next) {
if (elem > cur->value) break;
}
newOne->next = cur;
if (prev) {
prev->next = newOne;
logSize++;
} else {
head = newOne;
tail = head;
tail->next= NULL;
logSize++;
}
Your else clause is broken. If prev was null, then you are trying to insert before the first element.
else {
cell *oldHead = head;
head = newOne;
head->next = oldHead;
logSize++;
}
Setting tail->next = NULL is the core error.

C++ Add to linked list in sorted order

Hi I have a linked list using structs. Right now I got it to add every element at the end. However I'd like to add each element in sorted order based on the ID. The struct has two elements: string name, and long ID.
node* temp = new node;
temp->name = nameRead;
temp->id = idRead;
//check if first item, if so add as head
if(head == NULL)
{
head = temp;
}
else
{
node* temp2 = head;
while(temp2->next != NULL)
{
temp2 = temp2->next;
}
temp2->next = temp;
}
node* temp = new node;
temp->name = nameRead;
temp->id = idRead;
node* temp2 = head;
node** temp3 = &head;
while(temp2 != null && temp2->id < temp->id)
{
temp3 = &temp2->next;
temp2 = temp2->next;
}
*temp3 = temp;
temp->next = temp2;
EDIT: Explanation: The 'temp3' pointer points to where 'temp' would need to go. Initialize temp2 to head, and keep looping until we reach the end of the list, or until temp2's id is >= than temp's id. In each iteration of the loop, advance both temp3 and temp2.
At the end of the loop, 'temp3' will hold the address of the pointer where temp should be. So assign *temp3 to point to temp, and assign temp->next to point to temp2 (which at this point would either be null, or would point to the item that has larger id than temp->id).
Taken from my student notebook:
void addSorted(node * head, int id){
node* newNode = new node;
newNode->number = n;
newNode->next = NULL;
if(head == NULL || head->number >= id ){
newNode->next = head;
head = newNode;
return;
}else if(head->next != NULL && head->next->id >= id){
node * nextNode = head->next;
newNode->next = nextNode;
head->next = newNode;
return;
}else{
node * left;
node * right = head;
while(right != NULL && right->next->id <= id){
left = right;
right = right->next;
}
left->next=newNode;
newNode->next = right;
}
}
Most of the modification to the code is pretty trivial -- just add a comparison based on the ID so you only walk through the list until you get to a node with an ID larger then the new one you need to insert (or reach the end of the list).
This is where things get slightly tricky: before you "realize" you've reached the right spot in the list, you've already gone one node too far (and in a singly linked list, there's no way to go back). The trick to fix that is pretty simple: allocate a new (empty) node and insert it after the too-large node you found. Copy that too-large node's contents into the new one you just inserted, and then copy the data for the new node into the spot it just vacated.
I should add, however, that all of this is mostly a moot point. If you want a sorted collection of items, a linked list is usually a really lousy choice. Unless you're doing something like homework where you have no choice but to do whatever brain-dead crap you've been assigned, look up std::set [Edit: or std::multiset, if duplicates are allowed -- or possibly std::map or std::multimap, if you want to be able to find a node based on an ID] and forget about implementing it yourself.