I have a singly-linked, circular linked list and am writing a destructor to delete all the nodes. The destructor first severs the head from the rest of the lest to prevent infinite circulation and then I loop through the list and delete all the nodes, eventually, the loop comes back to the head and deletes it as well. In the program I check to make sure that the pointer to the nodes is not NULL and I ran the debugger and it shows that it is NULL at a point which should end the loop, but instead the loop continues and runs into un-allocated memory. Here is my code:
node<T> *cur = head;
node<T> *nxt = head->next;
if (nxt) cur->next = nullptr;
cur = nxt;
// walk through the list and delete nodes
while (cur) {
cur = cur->next;
delete cur;
}
EDIT: Changed code to
node<T> *cur = head;
node<T> *nxt = head->next;
if (nxt) cur->next = nullptr;
cur = nxt;
// walk through the list and delete nodes
while (cur) {
nxt = cur->next;
delete cur;
cur = nxt;
}
EDIT 2: Changed code once more to handle edge cases, same problem still occurs.
if (head == NULL) return;
else if (head->next == head) delete head;
else {
node<T> *cur = head;
node<T> *nxt = head->next;
cur->next = nullptr;
cur = nxt;
while(cur) {
nxt = cur -> next;
delete cur;
cur = nxt;
}
}
It has nothing to do with the severing, your code to walk the list while deleting elements would be just as faulty in a non-circular list. You advance the pointer then delete what it points to (the next item).
You need to delete the current item (but, of course, you also need to have extracted its next field before that point because, once deleted, all content becomes undefined), something like:
while (cur != nullptr) {
node<T> *toDelete = cur;
cur = cur->next;
delete toDelete;
}
In terms of a full solution to what you need, the algorithm should be:
def delCircList(head):
# Ignore empty list.
if head == null:
return
# Special for one-element list.
if head.next == head:
free head
return
# Sever link and set start point.
curr = head.next
head.next = null
# Use normal deletion algorithm.
while curr != null:
toDelete = curr
curr = curr.next
free toDelete
Related
I'm trying to delete every node at positions divisible by 5. With my approach I cannot seem to delete the last node:
void removeDivFive(Node* head){
int count = 0;
Node* temp = head;
while(temp != NULL){
count++;
if(count%5==0){
if(temp->next != NULL){
temp->value = temp->next->value;
temp->next = temp->next->next;
}
}
temp = temp->next;
}
while(head != NULL){
cout<<head->value;
head = head->next;
}
}
What I'm doing is copying the value of the next node to the current one and changing the pointer to the next next node. By doing this I cannot delete the last node if the list has 10 nodes.
Any help would be appreciated
First off, you are leaking the nodes you "remove". You need to actually destroy them since they are no longer being used.
Now, regarding your actual problem - what do you thing temp->next points at when the last node in the list is at a position divisible by 5? NOTHING! Thus, if (temp->next != NULL) evaluates as false, so you aren't even attempting to do anything with that last node, you just skip past it, which is why you are not removing it.
For every 5th node, you are copying the value of the next node into the current node, and then pointing the current node to skip the next node. In other words, you are not removing the 5th, 10th, 15th, etc nodes at all. You are actually removing the 6th, 11th, 16th, etc nodes instead. You need to remove the current node instead of the next node.
Which also means, you need to keep track of the previous node in the list so that you can re-link its next pointer to point at the next node that follows the current node being removed.
Try something more like this instead:
void removeDivFive(Node* head){
int count = 0;
Node *temp = head, *prev = NULL, *next;
while (temp != NULL){
++count;
next = temp->next;
if ((count % 5) == 0){
if (prev != NULL) {
prev->next = next;
}
delete temp;
}
else {
prev = temp;
}
temp = next;
}
}
Online Demo
Alternatively (as described by #GoswinvonBrederlow in comments):
void removeDivFive(Node* head){
int count = 0;
Node *temp = head, *next;
while (temp != NULL){
++count;
if ((count %4) == 0){
if (temp->next != NULL){
next = temp->next->next;
delete temp->next;
temp->next = next;
}
}
temp = temp->next;
}
}
Online Demo
As mentioned in the comments the deleted node isn't counted. So you need to delete a node every 4 counts instead of every 5. And if you use count%4 == 0 then the first time temp will point at node 4 and you want to delete the 5th node. So no need for temp->value = temp->next->value;, just remove the next node. Then next time around when count = 8 then temp will point at node 9. So again temp->next is the node to remove. ...
So the condition always fires for the node before the 5th, which is perfect for removing it.
void removeDivFive(Node* head){
int count = 0;
for (Node* temp = head; temp != NULL; temp = temp->next) {
count++;
if(count%4==0){
if(temp->next != NULL){
Node *t = temp->next;
temp->next = t->next;
delete t;
}
}
}
while(head != NULL){
cout<<head->value;
head = head->next;
}
}
Below fragment is invalid to inserting a node in the end of Linked List.
void insert_end(int item){
nodeptr newNode = new ListNode;
newNode->data = item;
newNode->next = NULL;
if(head == NULL){
head = newNode;
curr = head;
}else{
curr = head;
while(curr != NULL) curr = curr->next;
curr = newNode;
}
}
Another fragment that is valid to inserting a node in the end of Linked List.
void insert_end(int item){
nodeptr newNode = new ListNode;
newNode->data = item;
newNode->next = NULL;
if(head == NULL){
head = newNode;
curr = head;
}else{
curr = head;
while(curr->next != NULL) curr = curr->next;
curr->next = newNode;
}
}
My question is why 1st one is invalid? Actually two fragments should be similar.
Assume i have three nodes already. Now i want to inserting another node.
As first algorithm when curr = NULL, then while loop will not satisfied.
As second algorithm when curr->next = NULL then while loop will not satisfied.
so can i say first algorithm's 'curr' and second algorithm 'curr->next' both are similar, when "while loop" terminated?
if it's not similar then why?
You must understand a pointer is a variable which value is an address.
First algorithm is wrong because when you finish the iteration of while loop, curr points to NULL (address 0x0), and NULL is not a valid node of your list.
Second algoritm works because when you finish the iteration of while loop, curr points to last node of your list, and you add newNode to curr->next, replacing NULL by the address of newNode.
Hope this helps! :)
I have to write a method that's going to delete the last node from the List. Do you guys have any ideas on how I should approach this?
If you have a single-linked list, you have no choice but to iterate through the entire list to the last node, maintaining a pointer to the previous node so you can reset its next field when freeing the last node:
if (head)
{
node *curNode = head;
node *prevNode = NULL;
while (curNode->next)
{
prevNode = curNode;
curNode = curNode->next;
}
if (prevNode) prevNode->next = NULL;
delete curNode;
}
If you were using a double-linked list instead, this would be easier, as you can keep a pointer to the last node in the list and just operate on it directly:
if (head == tail)
{
delete head;
head = tail = NULL;
}
else if (tail)
{
node *curNode = tail;
tail = curNode->previous;
tail->next = NULL;
delete curNode;
}
Of course, if you are really using C++ then you should be using the STL's std::list (double-linked) or std::forward_list (single-linked) containers instead, which handle these details for you.
To delete the last element on a list all you need to do is maintain two separate nodes. Initially one should point to the head of the list and the other should point to the second element on the list. You should do something like the following :
if(head == NULL)
return 0;
else if(head->next == NULL){
Node *temp = head;
delete temp;
head = NULL;
}
else{
Node *one = head;
Node *two = head->next;
while(two->next != NULL){
two = two->next;
one = one->next;
}
one->next = NULL;
delete two;
}
The two lines of code at the bottom tail = head;
tail->next= NULL; causes the program to crash, when I call the extractMin() function. If i comment them out, everything is happening as supposed. Is this happening cause they are pointing to addresses in memory that has been freed?
The only clue the compiler gives me is this:EXC_BAD_ACCESS (code=2, address=0x0). I notice immediately the address being 0x0 so there is a problem there, but what exactly?
string LinkedListPQueue::extractMin() {
if (isEmpty())
error("Tried to dequeue from epmpty queue!");
cell *toBeDeleted = head; //pointer to this head
string value = head->value; //get value of this head
head = head->next; //move so this head is not the same as the one to be deleted
delete toBeDeleted; //delete previous head.
return value;
}
/* Implementation notes: enqueue
* -----------------------------
* We have to search to find the proper position, which can be a bit tricky with
* a singly-linked list. We walk two parallel pointers, one a step behind the other,
* until we find the correct position to insert the new cell, which we then splice
* into place. Note the special case of inserting at the head. Alternatively, this
* operation could work recursively.
*/
void LinkedListPQueue::enqueue(const string& elem) {
cell *cur, *prev, *newOne = new cell;
newOne->value = elem;
for (prev = NULL, cur = head; cur != NULL; prev=cur, cur = cur->next) {
if (elem > cur->value) break;
}
newOne->next = cur;
if (prev) {
prev->next = newOne;
logSize++;
} else {
head = newOne;
tail = head;
tail->next= NULL;
logSize++;
}
Your else clause is broken. If prev was null, then you are trying to insert before the first element.
else {
cell *oldHead = head;
head = newOne;
head->next = oldHead;
logSize++;
}
Setting tail->next = NULL is the core error.
Hello My problem with this code is on my 2nd else loop; i never enter it and therefore i never make new nodes for my list. can anyone help me see what i am missing?
bool List::Insert(int data)
{
Node* P = new Node;
if(P==NULL)
{
return false;
}
else
{
P ->info = data;
P ->next = NULL;
if(Head == NULL)
{
Head = P;
}
else
{
Node* lastNode;
for(lastNode = Head; lastNode ->next != NULL; lastNode = lastNode ->next)
{
lastNode ->next = P;
}
}
return true;
}
}
This:
Node* lastNode;
for(lastNode = Head; lastNode ->next != NULL; lastNode = lastNode ->next)
{
lastNode ->next = P;
}
is dead wrong. It will change the next pointer, for every single node currently in the list, to point to your new node. You need to only change the pointer in the last node:
Node* lastNode = Head;
while (lastNode->next != NULL)
lastNode = lastNode->next;
lastNode->next = P;
You may also, for efficiency, want to maintain a separate Tail pointer (in addition to your Head) so that you can simply replace that whole operation with:
Tail->next = P;
Tail = P;
That way, you won't have to traverse the entire list every time you want to append a new node. Your code then becomes something like (without the traversal, and with updating the tail pointer as well):
// Prepare new node.
Node *P = new Node;
P->info = data;
P->next = NULL;
// If list empty, set head and tail to new node, otherwise
// append it.
if (Head == NULL) {
Head = P;
Tail = P;
} else {
Tail->next = P;
Tail = P;
}
I'll stop short of criticising the fact that your Insert method doesn't actually insert but rather appends. My near-anal-retentive nitpicking nature is unlikely to endear me to you:-)
lastNode ->next = P; // this must go after the for