Linked List pop_back() function issues - c++

List.H
void List::pop_back()
{
if (size == 0)
cout << "The list is empty and there is no node to pop off the back of the list" << endl;
else if (size == 1)
{
delete tail;
head = tail = iterator = NULL;
}
else
{
NodeRef temp = tail;
while (iterator->next != NULL)
iterator = iterator->next;
tail = iterator;
delete temp;
size--;
}
}
void List::begin() //Set the iterator to the head of the list
{
iterator = head;
}
void List::push_front(int data) //Inserting a new node in the front of the list
{
if (size == 0) //If there is no nodes in the list, execute the if statement
{
head = new Node(data); //create a new node, and have head point to it
tail = head; //have tail point to the new node also.
}
else //If there are nodes in the list, execute the else statement
{
NodeRef newNode = new Node(data); //create a new node
newNode->next = head; //have the next pointer point to the head of the next node.
head = newNode; //have the head pointer point to the new node inserted at the beginning of the list
}
size++; //Increment the size counter
}
void List::print()
{
iterator = head; //Have iterator point to the head
if (size == 0)
cout << "There is nothing in the list" << endl;
else
{
while (iterator!= NULL)
{
cout << iterator->data << endl; //Display contents in node
iterator = iterator->next; //Move to the next node;
}
}
}
List.cpp
int main()
{
List B;
B.push_front(5);
B.push_front(4);
B.push_front(3);
B.begin();
B.pop_back();
B.print();
return 0;
}
So the issue I am having is that after the pop_back() function is called and I call the print() function. It has the last node popped but there is a junk number at the end of the list. I believe what is going on is that it is displaying the final node Next* which is an address. I know it has something to do with the else portion of the pop_back() and iterator->next causing it to point to an address.

You have two issues:
The else condition of your pop_back() function - You iterate through your list to get to the end, and you correctly release the memory of the last node, but you don't make the next pointer of the new tail point to NULL. The new tail's next pointer is still pointing to some random piece of unallocated memory and is actually a bug.
You aren't actually moving the tail pointer. Your inner while() loop just gets iterator to point to the same tail as before.
Try changing your else statement in pop_back() to:
iterator = head;
while (iterator->next->next != NULL) {
iterator = iterator->next;
}
tail = iterator;
delete tail->next;
tail->next = NULL;
--size;
This code assumes the size of your list is at least 2 (the above if statements take care of 0 and 1, so this should be fine for this code sample).

Related

Deleting node in a double linked list is not working

This is a basic function that takes an iterator position and deletes the node in this position but it gives me a runtime error. what am i doing wrong?
iterate erase(iterate position)
{
iterate i;
Node<T>* temp = head;
if (head == NULL) {
cout << "empty list" << endl;
}
else if (position.pointer == head) {
head = temp->next;
temp->next->previous = NULL;
delete position.pointer;
}
else {
while (temp != NULL) {
if (temp == position.pointer->previous) {
temp->next = position.pointer->next;
temp->next->previous = temp;
i.pointer = temp->next;
delete position.pointer;
return i;
}
}
}
Your function is lacking adequate return statements. There are multiple flows that can cause the function to exit, but only one of them has a return statement. So the return value will largely be indeterminate, causing undefined behavior for any caller that tries to use the return value.
In any case, your while loop iterates forever, because you are not updating temp on each iteration of the loop. You also have a NULL pointer dereference if position is pointing at the last node in the list, as you are not checking the new temp->next for NULL before accessing temp->next->previous.
But, you really don't need the while loop at all. The thing about a double-linked list is that, given any node in the list, you have direct access to the nodes that are surrounding it on both sides. So there is no need to iterate the list hunting for nodes.
Try something more like this instead:
iterate erase(iterate position)
{
Node<T> *temp = position.pointer;
if (!temp) return end();
Node<T> *next = temp->next;
Node<T> *previous = temp->previous;
if (next) next->previous = previous;
if (previous) previous->next = next;
if (temp == head) head = next;
//if (temp == tail) tail = previous;
delete temp;
iterate i;
i.pointer = next;
return i;
}
Alternatively:
iterate erase(iterate position)
{
Node<T> *temp = position.pointer;
if (!temp) return end();
Node<T> *dummy; // <-- only if no tail ...
Node<T> **previous = (temp->next) ? &(temp->next->previous) : &dummy/*&tail*/;
Node<T> **next = (temp->previous) ? &(temp->previous->next) : &head;
*previous = temp->previous;
*next = temp->next;
delete temp;
iterate i;
i.pointer = *next;
return i;
}

Pointer in deleting a node in single linked list

In place of *head_ref = temp->next;, why can't I assign it as *head_ref = *head_ref->next?
Why should I use temp? Aren't they pointing to the same place?
class Node{
public:
int data;
Node* next;
};
void deleteNode(Node** head_ref, int key){
Node* temp = *head_ref;
Node* prev = NULL;
if(temp!=NULL && temp->data==key){
*head_ref = temp->next;
delete temp;
return;
}
else{
while(temp!=NULL && *head_ref->data!=key){
prev = temp;
temp = temp->next;
}
}
Your code does not compile, *head_ref->data should be (*head_ref)->data.
The reason why you should use temp is that you want to modify *head_ref only if the element you want to delete is the head element. If you delete any other element of the list, the head pointer must stay the same.
But your code is wrong anyway. You're doing things in the wrong order. You must first find the element you want to delete, and then handle the deletion.
Your code handles the deletion first and then finds the element to delete which is absurd.
You want this:
void deleteNode(Node** head_ref, int key) {
Node* current = *head_ref;
Node* previous = NULL;
// find element to delete
while (current && current->data != key)
{
previous = current;
current = current->next;
}
// if current is NULL here then the element has not been found
if (current != NULL)
{
// element found,
// current points to element found
// previous points to previous element or NULL if current is head
if (previous == NULL)
{
// deleting head element -> we need to update head_ref
*head_ref = current->next;
}
else
{
// deleting any other element -> update next pointer of previous element
previous->next = current->next;
}
delete current;
}
}
That being said, this is rather C code than C++ code. You should use standard containers rather than making your own, or at least use C++ idioms such as constructors.

How can I check each 3 elements of a singly linked list and then delete some of them?

So basically I have this assignment on my University that asks to make a sorted singly linked list and then make some methods on it. The one that I'm having trouble is: "create delete() function that checks the average of each triple elements and if it's lower than integer 'K' (which is a parameter of said function) deletes the first element of the triple or deletes second and last element of the triple if it's higher."
I already made a function/method that deletes a single element of the linked list.
void LinkedList::deleteElement(int a)
{
Node *temp = head;
Node *previousTemp = head;
while(temp != nullptr)
{
if(temp->value == a)
{
break;
}
else
{
previousTemp = temp;
temp = temp->next;
}
}
if(temp == nullptr)
{
cout << "Can't delete. Element not found." << endl;
}
else
{
cout << "\nDeleting element: " << temp->value << endl;
previousTemp->next = temp->next;
delete temp;
}
howMany--;
}
void Sznur::deleteTriple()
{
Node *first = head;
Node *second = first->next;
Node *third = second->next;
}
The task is written pretty hard to understand but for ex.:
int K=3
linkedList: 7,6,6,3,3,3,2,1,1,1,1
after running the function:
linkedList: 7,3,1,1,1,1
(7+6+6)/3 > K -> deletes 6 and 6
(3+3+3)/3 > K -> deltes second 3 and last 3
(2+1+1)/3 < K -> deletes 2
If the linkedList length is not dividable by 3 the last elements stay in their place.
Try something like this.
void tripleFunc(Node* head, int K)
{
Node* nodePtr = head; // nodePtr always points at the start of a new triple
while (true)
{
Node* first = nullptr;
Node* second = nullptr;
Node* third = nullptr;
first = nodePtr; // When taking the three elements out, remember to always check for a null pointer BEFORE accessing the element
if (first)
second = first->next;
if (second)
third = second->next;
if (third)
nodePtr = third->next; // Keep the nodePtr pointing at the start of the next triple
else
return; // Only happens if one or more of the previous ifs failed, which means that we don't have enough elements left for a full triple
if (calculateAverage(first, second, third) < K) // Make this function
{
deleteElement(first->value);
}
else
{
deleteElement(second->value);
deleteElement(third->value);
}
}
}
I haven't tested it though, so any possible bugs are left as an exercise to the reader to find and sort out. :)

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
}

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