Hi I'm trying to delete a node in a linked list. I am first experimenting on how to delete the head and the tail nodes. The head deletion seems to work, however the tail the deletion does not. When I run the code, the place where the tail used to be is replaced with garbage values. Can anyone figure out why? Many thanks!
void CList :: Remove() {
int data = NULL;
std::cout<<"Enter value you wish to remove ";
std:: cin>> data;
cNode *pMyPointer = m_pHead;
while (pMyPointer != NULL)
{
if (pMyPointer->m_nValue == data) {
std::cout << "Element found";
goto del;
}
else {
pMyPointer = pMyPointer->m_pNext;
}
}
del:
//removing the head
if (pMyPointer == m_pHead)
m_pHead= m_pHead->m_pNext;
//removing the tail
else if (pMyPointer == m_pTail)
m_pTail = m_pTail->m_pPrev;
delete pMyPointer;
}
consider node_1 points to node_2 (just a 2 node case)
Just look at this code
else if (pMyPointer == m_pTail)
m_pTail = m_pTail->m_pPrev;
node_1 points to node_2 . It still points there . once you deleted node_2 , node_1 will still point to node_2 (or garbage once node_2 is deleted) & so you must make sure node_1 points to NULL . ie last but one should point to null .
something like
else if (pMyPointer == m_pTail)
m_pTail->m_pPrev->next=NULL;
m_pTail = m_pTail->m_pPrev;
With this statement
while (pMyPointer != NULL)
Your pointer may be pointing to NULL when it exits the loop and hence it will skip the tail pointer.
Instead try
while (pMyPointer->m_pNext != NULL)
You also need to make the second last node point to NULL.
else if (pMyPointer == m_pTail) {
m_pTail = m_pTail->m_pPrev;
m_pTail->m_pNext = NULL;
}
delete pMyPointer;
Also, instead of goto del, just use break;
Stay one node ahead of the node you want to delete
And what if your tail and head pointer are the same? You don't check for it. Therefore you might be deleting the pointer which you assume to be the Head, which is also a Tail. Plus what if it's Next for a Head or Prev for a Tail?
void CList :: Remove() {
int data = NULL;
std::cout<<"Enter value you wish to remove ";
std:: cin>> data;
cNode *pMyPointer = m_pHead;
while (pMyPointer != NULL)
{
if (pMyPointer->m_nValue == data) {
std::cout << "Element found";
goto del;
}
else {
pMyPointer = pMyPointer->m_pNext;
}
}
del:
//taking care of the neighbors
if (pMyPointer->m_pPrev)
pMyPointer->m_pPrev->m_pNext = pMyPointer->m_pNext;
if (pMyPointer->m_pNext)
pMyPointer->m_pNext->m_pPrev = pMyPointer->m_pPrev;
// removing the head
if (pMyPointer == m_pHead)
m_pHead= m_pHead->m_pNext;
//removing the tail
if (pMyPointer == m_pTail)
m_pTail = m_pTail->m_pPrev;
delete pMyPointer;
}
Related
I can't for the life of me figure this out I've spent days on this exercise but to no avail.
I'm trying to delete nodes with the value 0 from a singly liked list.
Let's say i have |1|3|0|4|0|5|0|0|. The outcome should be |1|3|4|5|
Here is all the code for reference
#include <iostream>
#include <fstream>
using namespace std;
struct node {
int data;
node* next;
};
node* head, *last;
int n;
void creating_list()
{
node* aux;
ifstream f("in.txt");
f >> n;
for(int i=0;i<n;i++)
{
if (head == NULL)
{
head = new node;
f >> head->data;
head->next = NULL;
last = head;
}
else
{
aux = new node;
f >> aux->data;
last->next = aux;
aux->next = NULL;
last = aux;
}
}
}
void displaying_list()
{
node* a;
a = head;
if (a == NULL)
cout << "List is empty! ";
else
{
cout << "Elements of list are: | ";
while (a)
{
cout << a->data<<" | ";
a = a->next;
}
}
}
void delete_first_node()
{
if (head == NULL)
cout << "List is empty";
else
{
cout << "Deleting first node\n";
node* aux;
aux = head;
head = head->next;
delete aux;
}
}
void delete_last_node()
{
if (head == NULL)
cout << "List is empty";
else
{
if (head == last)
{
delete head;
head = last = NULL;
}
else
{
node* current;
current = head;
while (current->next != last)
current = current->next;
delete current->next;
current->next = NULL;
last = current;
}
}
}
void delete_value_0()
{
node* aux;
if (head == NULL)
cout << "List is empty. Can't delete! ";
else
// if (head->data == 0)
// delete_first_node();
// if (last->data == 0)
// delete_last_node();
// else
{
node* a;
a = head;
while (a)
if (a->next->data != 0)
{
a = a->next;
cout << a->data<<" | ";
}
else
if (a->next != last)
{
aux = a->next;
a->next = a->next->next;
delete aux;
break;
}
}
}
int main()
{
creating_list();
displaying_list(); cout <<endl;
delete_value_0();
return 0;
}
Here is the problem that gives me metal problems
I've tried to move one node short of the node that has the 0 value, store the value in another node, aux in this case and delete aux;
I've put comment on those lines because if I don't and the condition it's met it doesn't execute the rest of the code...
If I put break at the end it only shows me the first few numbers until the 0 and then stops short, doesn't move through the full list.
if I don't put break the the program is doesn't stop, it's in an infinite loop, it doesn't exit with code 0
void delete_value_0()
{
node* aux;
if (head == NULL)
cout << "List is empty. Can't delete! ";
else
// if (head->data == 0)
// delete_first_node();
// if (last->data == 0)
// delete_last_node();
// else
{
node* a;
a = head;
while (a)
if (a->next->data != 0)
{
a = a->next;
cout << a->data<<" | ";
}
else
if (a->next != last)
{
aux = a->next;
a->next = a->next->next;
delete aux;
break;
}
}
}
Honestly I'm at a loss I've spent so much time trying to figure this out, and this should be a very simple exercise. I feel like the answear Is really simple but i don't know what to do anymore, Maybe this is not for me.
This is much simpler than it appears on the first glance. The trick to this task is instead of using a pointer to the current node, a pointer to the pointer to the current node gets used instead. The entire task becomes laughably trivial: only one loop, and one if statement that takes care of all possibilities: the list is empty; the node to delete is the first node in the list; ot the last node in the list; or anywhere in the middle of it.
void delete_value_0()
{
node **p= &head;
while (*p)
{
if ((*p)->data == 0)
{
node *nextptr=*p;
*p=(*p)->next;
delete nextptr;
}
else
{
p= &(*p)->next;
}
}
}
The naive solution is something like this:
void delete_value_0()
{
while (head && head->data == 0)
delete_first_node();
if (head == nullptr)
return;
node *cur = head->next;
node *pre = head;
while (cur)
{
if (cur->data == 0)
{
pre->next = cur->next;
delete cur;
cur = pre->next;
}
else
{
pre = cur;
cur = cur->next;
}
}
}
The key point is that you need to have a pointer to both the element you are inspecting and to the previous element in the list. This allows you to pull the current element out if it has data == 0.
The issue with this is that you have to treat the first element special (since it has no previous element).
My suggestion is to study this solution until you understand how it works, then move on to the (much better) solution by #Sam Varshavchik and study that - it does basically the same, but uses a pointer to pointer in a clever way to make the special cases here irrelevant.
I've put comment on those lines because if I don't and the condition it's met it doesn't execute the rest of the code...
OK why there the sketchy iteration is in else for if (last->data == 0)? Your input seems to have 0 as last item so in this case it would never be triggered. Also, if you want to have first/last items as special case, instead of
if (head->data == 0)
delete_first_node();
you would want something like
while (head && head->data == 0)
delete_first_node();
That being said, the real WTF is treating first/last item specially instead of using just single iteration. Also, you don't really check whether the pointers are non-null before trying to access the contents. With C (or C++ in the case you try it at some point) you need to take care with memory access when dealing with pointers.
Some random pieces of help:
You need to break from last item when it's 0 to exit loop simply because you don't assign a to the next item in this case.
If this is your schoolwork this might not be your fault, reading amount of items from the input file (assuming it was given part of the assignment) before actual items is huge WTF as you're reading into a linked list. There is no need to loop for any n items when you can be simply reading a line of input at the time until the file runs out.
Arguments and return values. You should learn those.
#include <iostream>
struct Node {
int data;
Node* next;
};
// Function to delete nodes with the value 0 in a singly linked list
void deleteNodes(Node** head) {
// Edge case: empty list
if (*head == nullptr) {
return;
}
// Delete all nodes with the value 0 at the beginning of the list
while (*head != nullptr && (*head)->data == 0) {
Node* temp = *head;
*head = (*head)->next;
delete temp;
}
// Edge case: list with only one node
if (*head == nullptr) {
return;
}
// Delete nodes with the value 0 in the rest of the list
Node* current = *head;
while (current->next != nullptr) {
if (current->next->data == 0) {
Node* temp = current->next;
current->next = temp->next;
delete temp;
} else {
current = current->next;
}
}
}
int main() {
// Create a singly linked list: 1 -> 0 -> 2 -> 0 -> 3 -> 0 -> 4
Node* head = new Node{1, new Node{0, new Node{2, new Node{0, new Node{3, new Node{0, new Node{4, nullptr}}}}}};
// Delete nodes with the value 0
deleteNodes(&head);
// Print the resulting list: 1 -> 2 -> 3 -> 4
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
return 0;
}
hope it help
I can't seem to understand what am I missing, I've spent hours and hours looking at this and everything I tried doesn't work.
My thought process to check if the second node of the list is even, if it is then to link the first and third node and delete the second but it doesn't work... I've been stuck at this for a week.
void delete_even()
{
nod *aux;
if (head == NULL)
{
cout << "List doesn't exist!";
}
else
{
nod *curent;
current = head;
while (curent)
{
if (curent->next->info % 2 == 0)
{
curent = curent->next->next;
curent->next = aux;
delete aux;
break;
}
else
{
curent = curent->next;
}
}
}
}
I don't know what else to do.
There are several things wrong with this code.
Your use of curent->next invokes undefined behavior when curent is pointing at the last node in the list, since next will be NULL in that case. It is are causing you to skip the 1st node in the list.
You never assign aux to point at anything, so calling delete on aux is also undefined behavior.
Even if aux were pointing at a valid node, you are assigning aux to curent->next right before deleting the node that aux is pointing at, thus leaving curent->next pointing at invalid memory, which is also undefined behavior.
If you did manage to remove a node from the list, you are breaking the loop immediately afterwards, so you would be removing only one even number from the list, not removing all even numbers, as your title suggests you want to do.
Try something more like this instead:
void delete_even()
{
if (!head)
cout << "List is empty!";
else
{
nod *curent = head, *prev = NULL;
while (curent)
{
nod *next = curent->next;
if (curent->info % 2 == 0)
{
if (prev)
prev->next = next;
else
head = next;
delete curent;
}
else
{
prev = curent;
}
curent = next;
}
}
}
Alternatively:
void delete_even()
{
if (!head)
cout << "List is empty!";
else
{
nod *curent = head;
nod **prev = &head;
while (curent)
{
if (curent->info % 2 == 0)
{
*prev = curent->next;
delete curent;
}
else
{
prev = &(curent->next);
}
curent = *prev;
}
}
}
I am working on an ordered linked list in C++. The task is to delete notes from the list and I've got two methods / functions to do that.
/*
* delete_head: Auxiliary function that deletes the first node of the list.
*/
book *delete_head(book*& deleteNode){
head = deleteNode->next;
delete deleteNode;
return head;
}
/*
* delete_node: Method that deletes a node from the list.
*/
void delete_node(int c){
book *aux = head;
// Verify list isn't empty.
if (head != NULL){
// Case 1: the head should be deleted.
if (aux->code == c){
head = delete_head(head);
} else {
book *aux2 = head->next;
while (aux2 != nullptr && aux2->code < c){
aux = aux2;
aux2 = aux2->next;
}
// Case 2: node wasn't found.
if (aux2 == NULL){
printf("Error: Node doesn't exist. \n");
} else {
// Case 3: the tail should be removed.
if (aux2->next == NULL){
aux->next = NULL;
delete aux2;
} else {
// Case 4: A node from the middle should be removed.
aux->next = aux2->next;
delete aux2;
}
}
}
} else {
printf("Error: Empty list. \n");
}
}
I've tested the code and the cases in which I delete the tail of the list or a node that's in the middle do work. The one that's giving me a bit of trouble is the case in which I need to delete the head and I'm not sure if it's related to the way pointers are handled.
Your helper function is borked:
book *delete_head(book*& deleteNode){
head = deleteNode->next;
delete deleteNode;
return head;
}
You call it with head = delete_head(head);, but when you do that deleteNode is set to a reference to the pointer to head. This means that anything you do to deleteNode you also do to head - and vice versa.
This means that here: delete deleteNode; you delete both deleteNode and head, which is a bit of a problem as you then return head.
Change the function to book *delete_head(book* deleteNode){ and it should do what you want.
I am having issues with deleting nodes in my doubly linked list, it crashes when I try to delete a node when there is only 1 node in the list. It works well otherwise. Its been driving me crazy because everything I have tried seems to make it worse not better. Here is my delete functions before I started changing them to try and get it to work better.
void doublyLinked::DeleteLast(int value) {
if (first == NULL)
cout <<" ERROR: You cannot delete what is not there. Please Try again! "
<< endl <<endl;
else {
Node* toDelete = last;
last = toDelete -> previous;
last->next = NULL;
delete toDelete;
}// end else
}// end function Delete Last
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void doublyLinked::DeleteFirst(int value) {
if (last == NULL)
cout <<" ERROR: You cannot delete what is not there. Please Try again! "
<< endl <<endl;// end if
else {
Node* toDelete = first;
first->next->previous = NULL;
first = toDelete->next;
delete toDelete;
}//end else
}
If there is only one entry, then first == last. Thus:
last = toDelete -> previous;
last->next = NULL;
is bad because after the first line last is NULL ;
Same with:
first->next->previous = NULL;
in the DeleteFirst()
Assume any next or previous pointer might be NULL and only use it after you've checked. Example:
if ( first->next && first->next->previous ) { first->next->previous= NULL ; }
Also note, your DeteleLast would need to modify first when deleting the last item.
I'd add test, if first == last. If so, delete it, and set both to NULL. Example:
if( first == last ) {
delete first;
first = last = NULL;
return;
}
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;
}
}