Deleting a node from the start of a linked list - c++

I am implementing a stack using a singly linked list where the Head is at the top of the stack and the Tail is at the bottom of the stack.
I am implementing a pop operation. In order to do this, I must make the head equal to the second node in the linked list. But before I do this, I need to delete the first node in the linked list first. I can do this using delete head->next;.
My question is, if I delete that first node, can I still use it to move on to the next node? Or is it bad practice to use a reference of a node that has had delete called on it. Here is the code I want to use to implement pop.
delete head->next;
head->next = head->next->next;

If you do:
delete head->next;
Then head->next is invalid. If you try to dereference it in the next line (remember the right hand side will be evaluated before the assignment), your program will crash.
head->next = head->next->!next; // dereference of the bad pointer happens where I put the !, and you crash there.
If you want to delete the object at head->next you will need to save it off first.
p = head->next;
head->next = head->next->next;
delete p;

First, once something is deleted, it is gone. Don't access deleted memory.
Second, why are you saying head->next = head->next->next? Shouldn't head = head->next be good enough for pop? In a empty list, head would be nullptr, wouldn't it?
Third, why are you not using std::list?
Last, order of operation is sometimes important, especially when the linked list might be shared by multiple threads. This is how I'd implement pop (and optionally make it multithread safe):
void list::pop() {
// optionally, acquire mutex
node* to_be_deleted = head;
head = head->next;
if (head == nullptr) tail = nullptr;
// release optional mutex here
delete to_be_deleted;
}

Related

Reverse a linked list, is my idea correct?

I was reading this: https://www.geeksforgeeks.org/reverse-a-linked-list/
I think I found an easier answer but since it wasn't written their and they used more complicated one I think something is wrong with mine and can't figure it out.
We start from the first node which we will copy and insert it into a new list.
then we go one step to the right, copy the value, create a new list with that value and setting its right the previous list and so on.
What's wrong with my algorithm?
If I interpret your idea correctly, it is something like this:
void forward_list::reverse() {
forward_list new_list;
for(auto& v : *this)
new_list.emplace_front(std::move(v));
std::swap(new_list, *this); // or *this = std::move(new_list);
}
... and this would work. It even looks pretty nice I'd say.
What's wrong with my algorithm?
It's creates a new node for every old node and then has to copy/move the data from the old node to the new node. The old nodes will then be destroyed.
Some types aren't even copyable or moveable so this reverse algorithm couldn't be used with such types.
It invalidates references and iterators.
Consider the alternative, reversing the links. It's a bit more complex but gets the job done without any of the drawbacks mentioned above.
Here's my take on reversing the links, which is not implemented exactly the same way as in the link you shared but it works pretty much in the same way. I think this one has fewer assignments though.
curr will point one step ahead of head and next is used to save the next pointer when the relinking is being done.
void forward_list::reverse() {
if(head) { // must have at least one node
node* curr = head->next; // head + 1
head->next = nullptr; // this will be the new last node
node* next; // for saving next while relinking
while(curr) { // while curr != nullptr
next = curr->next; // save the next pointer
curr->next = head; // relink backwards
head = curr; // move head forward
curr = next; // move curr forward
}
// head now points at the new start of the list automatically
}
}
Your algorithm is functionally correct, but since you are creating an entirely new list instead of reversing the existing nodes in-place, you are using twice the memory. You also have to deal with the cleanup of deleting the old nodes once you have your new list.

Linked List destructor without head?

I'm stuck on a linked list destructor for my class. This is what I have here:
LinkedList::~LinkedList()
{
LinkedList *forward = nullptr;
LinkedList *current = this;
//iterate through list, deleting each element as we go
while (current != nullptr)
{
//set next pointer to current's next
forward = current->next;
delete current; //delete the current memory
current = forward; //reset current to next's pointer
}
}
When I run it, I get a seg fault. I only want to delete just one node from my linked list. Is that possible? Also, I wasn't given a "head" pointer as I was used to from other lists, so I used "this" instead, does that work?
Aka - the .cpp is finding the spot in the linked list to delete, reorganizing the next pointers around it, and then deleting the node (which calls this destructor)
(when I run my program with an empty destructor, it prints out fine, but of course there are memory leaks)
Any help is appreciated!
by definition delete calls LinkedList::~LinkedList, so you have several (in fact infinite) calls to it because of the loop calling delete, so you access to already deleted element with an undefined behavior
just do
LinkedList::~LinkedList()
{
if (next != nullptr)
delete next;
}
or just
LinkedList::~LinkedList()
{
delete next; // delete on nullptr does nothing
}
even personally I prefer to compare to nullptr first
I argee with bruno.
Besides, when you want to delete a node and you don't have the pointer to head, you need a double-linked list.
The double-linked list has two pointers to its prev and next node.
when you need to delete a node, like this:
ListNode* p;
if(p->pre)
p->pre->nxt = p->nxt;
if(p->nxt)
p->nxt->pre = p->pre;
p->nxt = p->pre = NULL;
delete p;

why cannot "delete at head" work correctly when implementing link-list?

I implement the following code to delete element at Head. When program runes to "delete p", it will impact the previous Head and Head gets to NULL. What happened?
Node<T>* p;
p = Head;
Head = Head->next;
delete p;
This function will delete the 1st node (node
pointed to by head). It returns true if the node was deleted else false if the list is empty.
Using double pointers for the input parameter (head) here because head will
have to be updated and this value should reflect
outside this function.
bool deleteHeadElement(Node** head)
{
if (*head == nullptr)
{
// List is empty, nothing to delete
return false;
}
// Store the node that has to be deleted
Node* nodeToDelete = *head;
// Update the head to point to next nodeToDelete
*head = nodeToDelete->next;
delete nodeToDelete;
// 1st element of node has been deleted.
return true;
}
After the call to this function, you may subsequently call it and it will take care of the scenario in which the list becomes empty after the previous calls.
NOTE:
Regarding the value 0xfeeefeee, it seems you are trying to somehow freeing already freed memory. Perhaps you should check if your head is properly getting updated.
Also, make sure that you are freeing memory of the node by using delete only if it was allocated using new. delete takes care if the memory to pointed is NULL.
If you had allocated memory to the node using malloc(), you should be deallocating using free().

why do i need to return the head in a linked list?c++

NODE* InsertAtHead(NODE* &head, int val){
NODE *tmp = new NODE;
//create a new node
if (tmp == NULL)
exit(1);
//Initialize the new node
tmp->data = val;
tmp->next = NULL;
//Insert by changing links
tmp->next = head;
head = tmp; //update head
return head;
}
Why in the end we need to put return head?
The linked list you have is a singularly linked list. It only has references for next so you can only iterate to the end. If you have a pointer to the beginning you can get to everything, but if you have a pointer to the middle, you have no knowledge of the beginning.
In this function you are prepending, which creates a new beginning. If you don't return the new beginning then the calling function will have no knowledge of this element.
This is of critical impotance as you are using new to allocate memory and if it is not freed there will be a memory leak. It can't be freed unless the calling function has this pointer.
Linked list (when people say linked list they usually mean single linked list) has a link to the next node and no link to the previous one. So imagine if you return a node that is in the middle of list, you could get to next one and next one all the way to the end, this is good. Where you have a problem is that you will not be able to go to the previous node unless you have link to it, which would make it double linked list, or have pointer to the head first node in list which will serve as a start.
In your case you are pushing nodes onto the front of the list thus your code is pushing previous head to next and making new node a head node.
EDIT:
The head should be pass by reference. val should be passed by value. Why? For head we need an address of it so we could make a link to it. For val if we would pass it by reference, the address might be reused in caller function and we do not want our data to change.

Removing the head node of my linked list? C++

I have this somewhat unconventionally coded linked list and am trying to remove the head of it.
This is a hashtable, so it's an array of linked list
myStruct *pointer = HashTable[i];
1->2->3->NULL
How can I delete the 1 and make 2 the head of the list?
I've tried pointer = pointer->next but when I re-display the table, it still is printing 1->2->3->NULL, not 2->3->NULL.
I would recommend the image I made for you. I think it is safer than saying something like :
node *temp = head
head =head->next
delete temp
Because depending on how you handle your pointers, you could run the risk of deleting your whole list. Doing it this way, you will lose the head and make sure you have the rest of the list. But do what you like! man - try things out.
void changethehead(node*&head) {
node *tobedeleted = head;
head = head->next; // head is the next element
delete tobedeleted; // delete the old head
}