deletion in linked list - c++

This is my deletion code. The problem is that when i delete something from the tail or an nth node it works perfectly fine but whenever i delete something from the head it crashes. What check should i make in order to avoid the crash?
void List::Delete(int data) {
// Create a temp pointer
Node *tmp = head;
// No nodes
if ( tmp == NULL )
return;
// Last node of the list
if ( tmp->Next() == NULL ) {
delete tmp;
head = NULL;
}
else {
// Parse through the nodes
Node *prev;
do {
if ( tmp->Data() == data ) break;
prev = tmp;
tmp = tmp->Next();
} while ( tmp != NULL );
// Adjust the pointers
prev->SetNext(tmp->Next());
// Delete the current node
delete tmp;
}
}

If the node to delete is the head node, then this is what happens:
You declare Node *prev. Notice that it is uninitialised. Then you enter the do while loop, but break at the first if condition because tmp->Data() == data. So you exit the do while loop without executing the next statement, which would initialise prev. Now out of the loop, the next statement accesses the SetNext field of prev, whereas previous is unitialised. This is undefined behavior, and anything can happen; crashing is one such thing.
The way to avoid this is to add a check for whether prev is unitialised, or 'tmp' is the head node. In this case, you should delete the head, and return the node after head. Since your function has a void signature, you should delete the head node, and make the head pointer reference the node after head.

There are more than one problems with this code.
if ( tmp->Next() == NULL ) this check does not mean "Last node of the list" infact it means that there is only one node in the list since the code below only runs if there are at least two nodes you need to handle this case here.
tmp->Data() == data check is needed in addition to the above check to make sure that the only node in the list is also the node we want to delete before deleting it.
Node *prev = NULL; this pointer should be initialized so that we can check for NULL later to see if it is the head that needs to be deleted.
Also all the deletion should be done inside the loop checking for if ( tmp->Data() == data ) before the break; is applied, otherwise you will have no way to know if the loop ended naturally or was broken, to decide whether the node was found or not.
Here is the corrected code:
void List::Delete(int data) {
// Create a temp pointer
Node *tmp = head;
// No nodes
if ( tmp == NULL )
return;
// it is the only node in the list
if ( tmp->Next() == NULL && tmp->Data() == data ) {
delete tmp;
head = NULL;
}
else {
// Parse through the nodes
Node *prev = NULL;
do {
if ( tmp->Data() == data ){
if( prev == NULL ) // this is the head case
head = head->Next();
else // Adjust the pointers
prev->SetNext(tmp->Next());
// Delete the current node
delete tmp;
break;
}
prev = tmp;
tmp = tmp->Next();
} while ( tmp != NULL );
}
}
Note: The tail case works fine without any alterations in the code because, the only difference that this case creates, is that tmp->Next() for that case would be NULL which is exactly what we want for the new tail in prev->SetNext(tmp->Next()); i.e. set its Next to NULL.

Related

Is this code safe? (linked list, C++)

The following code seems to work ok to remove a node from a linked list:
bool remove(node * & head, int toBeRemoved)
{
if (head == nullptr) //empty list
return false;
else {
node * temp = head;
//the first node needs to be removed
if (head->data == toBeRemoved) {
head = head->next;
delete temp;
return true;
}
//seek for node and remove it
else {
while (temp->next != nullptr && temp->next->data != toBeRemoved)
temp = temp->next;
if (temp->next->data == toBeRemoved){
node * removeThis = temp->next;
temp->next = temp->next->next;
delete removeThis;
return true;
}
//data to be removed can't be found in the list
else
if (temp->next == nullptr && temp->next->data != toBeRemoved)
return false;
}
}
}
(I understand there's a list implementation in C++ but I'm only trying to understand this algorithm here, not replace it with something else).
Even though the code works when deleting a node placed at the beginning, in between or at the end of the list and I don't see any errors, I still have some doubts about the following line: if (temp->next->data == toBeRemoved).
Since that whole block can be executed when the node to be deleted is the last node (i.e.: temp->next==nullptr) I'm wondering how safe it is to attempt to access temp->next->data.
And even if it's safe, is it a bad programming practice?
No, that line is not safe.
The while loop ends when either temp->next is a null pointer, or temp->next->data contains the value to be removed. If it ends for the first reason, then accessing temp->next->data is invalid, because it's indirecting through a null pointer.
You should change the order of the test after the while loop ends. Check for the null pointer first. If it's not a null pointer, it means you found the element, and you can remove it.
while (temp->next != nullptr && temp->next->data != toBeRemoved) {
temp = temp->next;
}
if (temp->next == nullptr) { // data couldn't be found
return false;
} else { // data was found, remove it
node * removeThis = temp->next;
temp->next = temp->next->next;
delete removeThis;
return true;
}
}

Deletion of node at end of linked list 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;
}

Why isn't my remove node function working?

I've checked the boards and could not find any help with this. I find it easy to implement recursive functions given base and general cases, but this doesn't work the way I do it. I'm supposed to iterate down a list until I reach the tail of a linked list. If the next node is NULL, then I have to store the value at the last node, remove that node, and return the value. So it's similar to a dequeue method, except it's performed recursively. What am I doing wrong?
int LinkedList::removeTailRec(Node *n)
{
// check for the base case(s)
if(n->next == NULL)
{
Node *tmp = new Node();
tmp = n;
int val = n->value;
tmp = NULL;
return val;
}
else
return removeTailRec(n->next);
// else call the recursive method
}
First, I recommend you use nullptr instead of NULL.
Then, onto your code. You're actually not removing anything from your list.
if(n->next == NULL)
{
Node *tmp = new Node();
^^^^^^^^^^
//Useless, and dangerous. This memory is never free'd
tmp = n;
int val = n->value;
tmp = NULL;
^^^^^^^^^^
//You just set a local variable to NULL, you're not deleting anything
return val;
}
If you want to remove the node, you'll have to keep a reference to the previous node (e.g. having a doubly linked list, that is, having a pointer to the next element and a pointer to the previous element in each node, or working on the previous node directly).
Set this previous node's next to nullptr, store the node's value and then delete the Node pointer.
One way to do this is to work with the pointer to the next node :
int LinkedList::removeTailRec(Node *n)
{
//EDIT: Adding a check for n validity
if(!n){
//Here, you should have a way of detecting
//a call to your method with a null pointer
return 0;
}
Node* nextNode = n->next;
// check for the base case(s)
if(nextNode->next == nullptr)
{
//Get the next node value
int val = nextNode->value;
//Set the current node next member to nullptr
n->next = nullptr;
//Free the last node
delete nextNode;
return val;
}
else{
return removeTailRec(n->next);
}
// else call the recursive method
}
You are storing the result but not deleting it from linked list. You can return result in another variable (pointer : result).
Node* getTail(Node *n,int *result){
//u can even free the memory
if(!n->next)
{
result=n->value;
return NULL;
}
n->next=getTail(n->next,result);
}
or you can do it other way
int getTail(Node *n)
{
if(!n) return 0;
if(n->next)
{
if(!n->next->next)
{
Node *frnode=n->next;
int result=n->next->value;
n->next=NULL;
delete frnode;
return result;
}
getTail(n->next);
}
You are not removing last node in your code, and you leak another (temporary) node here.
To remove last node you have to zero the link in the previous node.
Your code should look like
...
if (n == NULL || n->next == NULL)
throw std::out_of_range("node");
if(n->next->next == NULL)
{
int val = n->next->value;
delete n->next;
n->next = NULL;
return val;
}
else ...
Be aware of the fact that c++ is not a functional language and has no optimizations for tail recursion, so in real application as your lists grow big enough you'll eventually have failure with stack overflow =) use Haskell or Erlang for this style of programming, in c++ use for or while.
You should set the Node n's previous Node's next field to NULL when n is the tail Node.

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

Delete a node from the middle of a C++ queue

I have a linked list with a c-style ctor and dtor.
I just got too frustrated when this if statement decided not to test true, putting me in
an infinite loop. I dont understand why it will never test true.
I am trying to delete a node (the address of a class object) from my LinkedList.
Maybe someone could help me out?
Node *Current = first_; // I want this to be my only Node Ptr Varaible Declaration.
if ( NULL == first_ )
std::cout << "Cannot delete from an empty list: \n";
while ( Current != NULL )
{
if ( first_->data_ == node->data_ )
{
//check to see if we are deleteing the head.
first_ = first_->next_;
--listLen_;
delete Current;
std::cout << "Head Deleted!\n";
}
if ( Current->data_ == node->data_ ) // FOR SOME REASON this is never true?
{
--listLen_;
node->data_ = NULL;
Current = Current->next_;
node->data_ = Current;
}
else // we must not of found it. // else should match previous i
{
Current->prev_ = Current;// since we are not deleting the first node we are OK here.
Current = first_->next_;
if ( Current->next_ == NULL ) // see if we are at the end of the list.
{
first_ = NULL;
last_ = Current->prev_;
}
}
}
return;
This should really be rewritten, since it has too many problems...also why not use a STL container? I assume this is a homework question.
The answer to the infinite loop is the else case that increments to the next node:
Current = first_->next_;
This will make you loop forever if the data is not found in in the first two nodes...since you will set the next test to the first's next node always and it will never set the current to NULL provided there are more than 2 nodes in the list.
Keep your loops small, it easier to figure out what went wrong. Assuming your data compare makes sense, look at this the following:
curr = first_;
while( curr && (curr->data_ != node->data_) ) {
curr = curr->next_;
}
if (!curr) return // didnt find it, nothing to remove
if ( curr == first_ )
first_ = curr->next_
else
curr->prev_->next_ = curr->next_
curr->next_->prev_ = curr->prev_ // always fix next's prev
delete curr
I'm not entirely sure what you're trying to accomplish, but I'm certain you're doing it wrong. If you're merely trying to remove an element from a doubly-linked list that matches node->data_, it's as easy as this:
Node *Current = first_;
while (Current != NULL)
{
if (Current->data_ == node->_data)
{
//If Current isn't the head of the list, set prev to next
if (Current != first_)
Current->prev_->next_ = Current->next_
else
{
first_ = Current->next_;
if (first_ != NULL)
first_->prev_ = NULL;
}
//If Current isn't the tail of the list, set next to prev
if (Current->next_ != NULL)
Current->next_->prev_ = Current->prev_
else if (Current->prev_ != NULL)
Current->prev_->next_ = NULL;
delete Current;
Current = NULL;
}
else
{
Current = Current->next_;
}
}
return;
You don't show where node comes from or how data_ is defined, but if it is a pointer type, you probably need to compare the contents, not the addresses.
Assuming that data_ is a pointer to something and what it points to has operator== defined or is a built in type and it has the value you are looking for then you can do this instead:
if ( *Current->data_ == *node->data_ )
if first_->data_ == node->data_ ever evaluates to true then the second if statement will always evaluates to true then the second if condition will always evaluate to false Current->data_ == node->data_ because on the first iteration first_ == Current and you delete Current without ever updating it
To delete a node from a linked list you seem to be doing way too much work.
Not really an answer here for the actual question but a suggestion.I would never iterate through a linked list to delete an entry in the list. Each entry should have a valid next and previous pointer and when you go to delete an entry from the list you just make the previous record point to the next one and vice versa to remove yourself from the list. An empty list should have a head record and a tail record that just point to each other and all valid entries are inserted in between.
Delete a node with value passed.
void deleteBegin()
{
Node* temp =Head;
if(temp==NULL)
return;
Head=Head->next;
free(temp);
}
void deleteMiddle(int _data)
{
Node* curr = Head;
Node* prev = Head;
if(curr==NULL)
return;
if(curr->next==NULL)
{
deleteBegin();
return;
}
while(curr->next!=NULL && curr->data!=_data)
{
prev=curr;
curr=curr->next;
}
if(curr->data == _data)
{
if(prev==curr)
{
deleteBegin();
return;
}
prev->next = curr->next;
free(curr);
}
else
{
cout<<"Element Not Found\n";
return;
}
}