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;
}
}
Related
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;
}
}
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.
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'm trying to make a linked list that gets words from the user until the input is blank, and every word is added so the list stays in alphabetical order. However, only the first node is printed. Is there something I'm doing wrong? Here's what I have (minus the header and declarations):
//put in additional nodes until the input is blank
while(in != " "){
cin >> in;
newPtr->data = in;
prevPtr->data = "";
prevPtr->next = NULL;
nextPtr = list;
//shift the prevPtr and nextPtr until newPtr is alphabetically between them
while(!(prevPtr->data<=in && nextPtr->data>in)){
prevPtr = nextPtr;
nextPtr = prevPtr->next;
}
//make newPtr point to the next node
if(nextPtr != NULL){
newPtr->next = nextPtr;
}
//make newPtr the "next" pointer of the previous node, if any
if(prevPtr != NULL){
prevPtr->next = newPtr;
}
//if there's nothing before newPtr, make it the first node
else{
list = newPtr;
}
printList(list);
};
}
I would post this as a comment, because I am afraid I might be missing something, but I can't yet do this, so here goes a non-answer:
What keeps you from using the std::list? You can insert a word, check if it is non-empty, immediately apply a the standard sorting algorithm (It relies on the comparison operators of the sorted objects) and print it. It is fast, your code is short and readable and you don't spend your time reinventing the wheel.
PS: If you want to test for an empty string it should be "", not " " , I think.
I think there is a number of issues here.
For one in the initial iteration what is prevPtr->data pointing at? If it's pointing at nothing or hasn't been allocated to any memory you shouldn't be setting this to anything yet.
Plus you need to allocate memory for newPtr on every iteration, otherwise you are just writing over the memory location of where it is pointing to last from the in the list.
Second lets assume that prevPtr is pointing to something, on the second iteration (or more) of this while loop prevPtr has been moved farther down the list (prevPtr = nextPtr) which would cause prevPtr->data = " " to erase any data in that element. So you could be printing the first node plus a bunch of spaces afterwards.
Third you should check if list is NULL first in your loop, because if loop is NULL, nextPtr->data would be pointing at junk which is not good. This NULL check on list could be your corner case of the first element.
Try something like this, I didn't have time to test it but it should get going in the right direction:
Node *list = NULL;
while(in != " "){
cin >> in;
Node *newPtr = new Node();
newPtr->data = in;
newPtr->next = NULL;
prevPtr = list;
nextPtr = list;
// Do we have an empty list
if(list != NULL)
{
// Corner Case: First on the list
if(newPtr->data <= prevPtr->data)
{
list = newPtr;
newPtr->next = prevPtr;
}
else
{
// CASE: Somewhere between the first and the list
while(nextPtr->next != NULL)
{
nextPtr = nextPtr->next;
if(newPtr->data >= prevPtr->data && newPtr->data <= nextPtr->data)
{
prevPtr->next = newPtr;
newPtr->next = nextPtr;
break;
}
prevPtr = prevPtr->next;
}
// Corner Case: end of list
if(nextPtr->next == NULL)
{
nextPtr->next = newPtr;
}
}
}
else
{
// Corner Case: We had an empty list
list = newPtr;
}
printList(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;
}
}