How to delete a linked list without recursion? - c++

I'm trying to find a way of deleting a linked list without recursion, because a stack overflow isn't really something nice.
I have a struct as follows:
typedef struct _my_Item
{
_my_Item(const std::string& name)
{
m_name = name;
}
~my_Item()
{
delete next; // this recursively deletes the "tail" of the list
next = NULL;
}
struct _my_Item *next;
std::string m_name;
// ... More members here...
}
In some piece of code (not relevant here) I'm constructing a list from a data file using the above structure. I keep the pointer to the head of the list in a variable and can work with it. All fine.
When I finally call the destructor on the head of the list, the destructor gets called and the delete next; causes a recursion to delete the "tail" of the list (which is the entire list without the first element). Now since the list is quite long, I see a stack overflow sometimes.
Is there a nice way to get around this problem?

~my_Item()
{
while (next)
{
_my_Item* item = next;
next = item->next;
item->next = NULL; // this prevents the recursion
delete item;
}
}

Create a class representing the list itself that will encapsulate nodes deletion in its destructor via a for/while loop. Doing it the way you do leaves the possibility to delete part of the list and leave dangling pointer.

One suggestion would be to remove the delete code from the destructor and use a pointer to delete the list.
struct _my_Item * nodeToDelete = NULL;
while(firstNode != NULL)
{
nodeToDelete = firstNode;
firstNode = firstNode->next;
delete nodeToDelete;
}

// I wrote this java code to delete a node from BST
// I only used one recursion call to remove successor
public Boolean delete(int data){
if(isEmpty() || !search(data))
return false;
return delete(null,root,data);
}
public Boolean delete(Node parent,Node temp,int data) {
while(true){
if(data == temp.getData()) {
break;
} else if(data < temp.getData()) {
parent = temp;
temp = temp.getLeft();
} else {
parent = temp;
temp = temp.getRight();
}
}
if(parent == null && (temp.getLeft() == null || temp.getRight() == null)){
if(temp.getLeft() == null)
root = temp.getRight();
else
root = temp.getLeft();
} else if(temp.getLeft() == null || temp.getRight() == null) {
if (parent.getLeft() == temp) {
if (temp.getLeft() == null)
parent.setLeft(temp.getRight());
else
parent.setLeft(temp.getLeft());
} else if (parent.getRight() == temp) {
if (temp.getLeft() == null)
parent.setRight(temp.getRight());
else
parent.setRight(temp.getLeft());
}
}else{
int min = findMin(temp.getRight());
temp.setData(min);
delete(temp,temp.getRight(),min);
}
return true;
}

Related

Creating an ordered linked list of a class object

bool CharacterList::addCharacter(Character *newCharacter)
{
Character *temp, *back;
if(head == NULL)
{
head = newCharacter;
}
else
{
temp = head;
back = NULL;
while((temp != NULL) && (temp < newCharacter))
{
back = temp;
temp = temp.next;
}
if(back == NULL)
{
newCharacter.next = head;
head = newCharacter;
}
else
{
back.next = newCharacter;
newCharacter.next = temp;
}
return true;
}
}
I'm creating an ordered linked list(CharacterList) for the objects of class Character. This function will take only one argument, a pointer to a Character class object(*newCharacter). It will then add this character to the linked list of character objects. I'm not sure if this is how I insert an object to the linked list. can someone guide me please ?
Instead of reinventing your own, you should use std::list, as follows:
std::list<Character> CharacterList;
But please read a good book before going any further.

C++ Add node to beginning of linked list fails after 1 time. Trouble with other methods too

So I have a linked list program semi working. I am just having some trouble with certain methods.... The ones I have documented bekiw are working except for delete from end which is acting weird.
I am using NetBeans on Mavericks with G++ as my compiler and C++11
Here is a zip of all of the program files
Here is a list of the methods I am trying to make:
//working
int size() const;
/kind of
void addToStart(Node *);
//working
void addToEnd(Node *);
//working
void printList();
//working
bool removeFromStart();
//kind of working
bool removeFromEnd();
//Still working on these
void removeNodeFromList(int);
void removeNodeFromList(string);
For now, I have to run removeFromEnd() twice in order for it to work. Meaning, I run it once at the beginning of the program and it does nothing, but every subsequent time, it actually does the deleting.
For addToStart() it works if I only run it once. I.E:
I can run it once at the beginning of the program and print out the list
I can run it once AFTER using addToEnd, but if I try it a second time, and I try to print out the list, it just keeps spitting out the value I tried to add.
addToEnd() works perfectly find if I just keep running that, but it fails if I:
Start out by using addToEnd() to add items, then use addToStart() ONCE and THEN try to use addToEnd() again. When I print out the list, it only prints out two objects and each of those is a copy of the last value I tried to insert.
void LinkedList::addToEnd(Node* ne)
{
Node** q = &myHead;
while (*q)
{
q = &(*q)->next;
}
*q = new Node(ne->itemName, ne->itemNo);
}
void LinkedList::printList()
{
Node* p = myHead;
while (p != NULL)
{
cout << p->itemNo << " " << p->itemName;
cout << endl;
p = p->next;
}
cout << endl << endl;
}
bool LinkedList::removeFromStart()
{
if (myHead == NULL)
{
cout << "List is already empty";
}
else
{
myHead = myHead->next;
}
}
bool LinkedList::removeFromEnd()
{
if (myHead == NULL)
return false;
//Empty the list if there's only one element
if (myHead->next == NULL)
{
delete myHead;
myHead = NULL;
myTail = NULL;
return true;
}
// Find the last item in the list
Node *temp = myHead;
while (temp->next != myTail)
{
temp = temp->next;
}
delete myTail;
temp->next = NULL;
myTail = temp;
return true;
}
Also, still trying to figure out the remove ones
void LinkedList::removeNodeFromList(int i) {
//Save the values
Node* p = myHead;
Node* temp = myHead->next;
while (p) {
if (p->itemNo == i) {
p=temp;
} else {
p = p->next;
}
}
}
You have a tail pointer, so why are you iterating through the list to find the end? Additionally, why are you passing the node by pointer?
void LinkedList::addToEnd(Node ne)
{
if (myHead == nullptr) // empty list
{
myHead = myTail = new Node(ne);
myTail->next = nullptr;
}
else
{
myTail->next = new Node(ne); // assuming Node has an accessible copy constructor
myTail = myTail->next;
}
}
The removeFromStart function has a memory leak:
bool LinkedList::removeFromStart()
{
if (myHead == nullptr)
{
cout << "List is already empty";
return false;
}
Node* temp = myHead;
myHead = myHead->next;
if (myTail == temp) // if there is only 1 element in the list, head == tail
{
myTail = myhead;
}
delete temp;
return true;
}
Presumably, removeFromEnd should be removing the tail:
bool LinkedList::removeFromEnd()
{
if (myTail == nullptr)
return false;
// unless you have a doubly-linked list, loop to find 1 before the tail
Node* temp = nullptr;
for (temp = myHead; temp && temp->next != myTail; temp = temp->next);
if (myHead == temp) // when there is only 1 element in the list, head == tail
{
delete temp->next;
myHead = nullptr;
myTail = nullptr;
}
else
{
delete temp->next;
temp->next = nullptr;
myTail = temp;
}
return true;
}
And yes, you are using new (in your addtoEnd function), so you must use delete (not free!).
Side note: You can write the remove code better by using std::unique_ptr (you can actually improve the code overall by using it everywhere) which will make your code for each about 4 lines long. I'll leave that for you to implement.
You have a member called myTail that you seem to be using 'sometimes'
In addFromEnd you do not update myTail.
In one of the remove functions you do not update myTail even though you might change it
But in RemoveFromTail you are trying to use it.
There is no reason that myTail will contain a valid value and when you try to use it you can get an error (cause the node may have been deleted) or an unexpected result because it just points somewhere in the list.
You should either lose it (since you can easily figure out the tail. it is the node where next==NULL) or take care to maintain it in every call that changes the List (only if the tail is affected obviously)
Since you are using c++11 a few suggestions:
use nullptr instead of NULL
use std::unique_ptr for Next. It will take care of 'deleting' nodes you are no longer using for you.
use a copy ctor for Node. If you ever make a change to Node you will not need to revisit this part of the code just the constructors.
If you are holding copies of objects in the list. Then it is much clearer if your interface will accept const Node& instead of Node*. To me Node* makes it seem like you are going to use the ptr the user supplied.

Stack overflow with my destructor

this is my first post to stack overflow. I'm creating a program to parse text into a linked list alphabetically, and to keep track of the count of each word. The program runs fine (by fine I mean 15 minutes which is obviously slow and not using a strong data structure) until my program returns and tries to deconstruct the dynamically allocated memory. Could someone help identify what pieces of this code I may need to adjust to avoid overflowing my stack?
template <class T>
void WordList<T>::destroyWord(WordList<T> *node)
{
WordList<T>* nodeD = NULL;
for(; node != NULL; )
{
if(node == NULL)
return;
else if(node->mNext != NULL)
{
nodeD = node;
node = node->mNext;
}
else
{
// We have found the node to delete.
//destroyWord(node->mNext);
if( node->mNext == NULL )
{
if( nodeD != NULL )
{
nodeD->mNext = NULL;
delete nodeD;
}
else
{
node = NULL;
}
}
nodeD = NULL;
}
}
// **********************************
// Delete the node at the root.
//delete node;
return;
}
Here is my revised code, thanks guys!....
template <class T>
void WordList<T>::destroyWord(WordList<T> *node)
{
node = node->mRootNode->mNext;
static WordList<T>* ptr = node;
for(; node != NULL && node->mNext != NULL; )
{
ptr = node->mNext;
delete (char*)node;
node = ptr;
}
delete (char*)ptr;
}
I would bet: your destructor most probably calls destroyWord. We can see that the destroyWord has a delete nodeD; statement. nodeD is type of WordList<T>, so this will cause a destructor call on WordList<T>, and that has a delete nodeD; as we have seen. There is our infinite recursion.

Removing a node from a linked-list

I've created a Hash-table and I want to remove a node from the linked-list. The code works for removing the first node but not for removing others.
void intHashTable::remove(int num){
int location = ((unsigned)num) % size;
Node * runner = table[location];
int checker;
if(runner->next == NULL){
if(num == table[location]->num){
table[location] = NULL;
}
}else{
if(table[location]->num == num){
table[location] = table[location]->next;
}else{
//This part doesn't seem to be working.
Node *temp = runner->next;
while(temp != NULL){
if(temp->num == num){
runner->next = temp->next;
delete(temp);
break;
}
}
}
}
}
You haven't updated temp to point to the next item within the loop:
temp = temp->next;
You also appear to represent an empty row with a NULL pointer in your table, but you don't handle this case properly in your code - if runner is NULL then you'll crash when you try to access runner->next in the first check. Also, you're failing to delete the node in some cases.
To fix these issues, you can update your code to something like this:
void intHashTable::remove(int num)
{
int location = ((unsigned)num) % size;
Node * runner = table[location];
if (runner != NULL) {
if (runner->num == num) {
delete runner;
table[location] = NULL;
} else {
while (runner->next != NULL) {
if (runner->next->num == num) {
Node *temp = runner->next;
runner->next = runner->next->next;
delete temp;
break;
}
runner = runner->next;
}
}
}
}
Also note that I've removed the brackets from delete, which is a C++ keyword and not a function.
If you use doubly-linked lists (i.e. with a previous pointer as well as a next) then you can simplify this code a little, although for something like a hash table where you only tend to iterate through in one direction it's probably not worth the expense of the extra pointer (an extra 8 bytes per item on a 64-bit system).
You didn't updated temp and runner variables inside loop:
while(temp != NULL)
{
if(temp->num == num)
{
runner->next = temp->next;
delete temp;
break;
}
runner = temp; // Keep previous element to change its next pointer when num found
temp = temp->next; // Advance current pointer to next element
}

adding node at last in Linked List in C++

I have tried to implement Singly Linked List. My addAtLast() function is not getting executed properly. Program crashes while executing this function. Kindly suggest some changes.
class LList
{
public:
int noOfNodes;
Node const *start;/*Header Node*/
LList()
{
start=new Node;
noOfNodes=0;start=0;
}
void addAtFront(Node* n)
{
/*
cout<<endl<<"class"<<n;
cout<<"start"<<start;
cout<<"data in node";n->print();
*/
n->next=const_cast<Node*>(start);
start=n;
// cout<<" next=";start->print();
noOfNodes++;
}
void addAtLast(Node* n)
{
Node *cur=const_cast<Node*>(start);
if (start==NULL)
{
start=n;
return;
}
while(cur->next!=NULL)
{
cur=cur->next;
}
cur->next=n;
noOfNodes++;
}
int getPosition(Node data)
{
int pos=0;
Node *cur=const_cast<Node*>(start);
while(cur!=NULL)
{
pos++;
if(*cur==data)
{
return pos;
}
cur=cur->next;
}
return -1;//not found
}
Node getNode(int pos)
{
if(pos<1)
return -1;// not a valid position
else if(pos>noOfNodes)
return -1; // not a valid position
Node *cur=const_cast<Node*>(start);
int curPos=0;
while(cur!=NULL)
{
if(++curPos==pos)
return *cur;
cur=cur->next;
}
}
void traverse()
{
Node *cur=const_cast<Node*>(start);
while(cur!=NULL)
{
// cout<<"start"<<start;
cur->print();
cur=cur->next;
}
}
~LList()
{
delete start;
}
};
void addAtLast(Node* n) {
Node *cur=const_cast<Node*>(start);
if(start==NULL) {
start=n;
n->next = NULL;
noOfNodes++;
return;
}
while(cur->next!=NULL) {
cur=cur->next;
}
cur->next=n;
n->next = NULL; // Added
noOfNodes++;
}
I mentioned this in-comment, but will address it here as an answer. The caller of this function must ensure two things:
That the passed-in node list (and it is a list, even if only one element long) must be properly terminated with an end-next-pointer set to NULL. The caller must ensure this, as this code cannot assume it and blindly set node->next = NULL;
Make absolutely sure the caller is aware that once this executes, this list now owns the passed-in node and any list it potentially starts and the caller, therefore, must NOT free it, or anything it points to, on the caller side.
Apart from the node-count management issue, there is nothing wrong with the addAtLast() function, though I would have implemented it a little differently:
void addAtLast(Node* n)
{
// no nulls allowed
if (n == NULL)
return;
// set start if first in list
if (start == NULL)
{
start = n;
noOfNodes = 1;
}
// else walk list to find end
else
{
Node *cur = const_cast<Node*>(start);
while(cur->next != NULL)
cur = cur->next;
cur->next = n;
++noOfNodes;
}
// adjust count to contain any nodes from 'n'
while (n->next != NULL)
{
++noOfnodes;
n = n->next;
}
}
From the beginning..
start=new Node;
noOfNodes=0;start=0;
Should this be?
start=new Node;
noOfNodes=0;start->next=NULL;
Within 2 lines you've created memory leak. I have no idea why you would want to set start=0. Don't do that, you've just assigned memory to it!
As for the crash, it's addressed by #liulinhuai's answer. You'll be dereferencing a pointer that is uninitialized attempting to get it's next member.
In your ctor you set start as 0. In your crash function you first check it for NULL:
if (start==NULL)
{
start=n;
//n->next is now points to nowhere
return;
}
Next call to addAtLast iterate until it finds NULL but previous assign didnt set next pointer to NULL so second iteration will cause an access violation:
while(cur->next!=NULL) {
//first time it's ok but second call on cur will crash
cur=cur->next;
}
Solution is - all new Node's must have next pointer setted to NULL