I wrote a small code to detect the largest number in the binary tree, it is working just fine, its simple, it goes far down to the last right node(leaf in case) and then i just cout<< it, now i would like to delete it, i looked trough some similar question, but i only need to delete the number i got back from the search, but my prog just crashes after i run it list the tree get the number, delete and try to list it again.
Here is my search:
T Remove( Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return theRoot->data;
}
Here is the full code:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
template<class T>
class BinaryTree
{
struct Node
{
T data;
Node* lChildptr;
Node* rChildptr;
Node(T dataNew)
{
data = dataNew;
lChildptr = NULL;
rChildptr = NULL;
}
};
private:
Node* root;
void Insert(T newData, Node* &theRoot)
{
if(theRoot == NULL)
{
theRoot = new Node(newData);
return;
}
if(newData < theRoot->data)
Insert(newData, theRoot->lChildptr);
else
Insert(newData, theRoot->rChildptr);
}
void PrintTree(Node* theRoot)
{
if(theRoot != NULL)
{
PrintTree(theRoot->lChildptr);
cout<< theRoot->data<<" \n";
PrintTree(theRoot->rChildptr);
}
}
T Largest( Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return theRoot->data;
}
T Remove(Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return ;
};
public:
BinaryTree()
{
root = NULL;
}
void AddItem(T newData)
{
Insert(newData, root);
}
void PrintTree()
{
PrintTree(root);
}
T Largest()
{
return Largest(root);
}
//void Remove()
//{
// Remove(root);
//}
};
int main()
{
BinaryTree<int> *myBT = new BinaryTree<int>();
myBT->AddItem(2);
myBT->AddItem(20);
myBT->AddItem(5);
myBT->AddItem(1);
myBT->AddItem(10);
myBT->AddItem(15);
//for(int i = 0; i < 10; i++) //randommal tolti fel
//myBT->AddItem(rand() % 100);
cout << "BinaryTree:" << endl; //kilistazaa a fat
myBT->PrintTree();
cout << "Largest element: " << myBT->Largest() << endl; //visszaadja a legnagyobb elemet
//myBT->Remove();
myBT->PrintTree();
}
the actual delete function is in // comments so i can run the prog.
You are deleting theRoot and then trying to dereference it. If you want to return the value stored in the node you need to make a local copy first like this:
T value = theRoot->data;
delete theRoot;
return value;
Is the return thetRoot->data; line intended to be part of the else statement? If so you need to add brackets around it like this:
if (theRoot->rChildptr != NULL)
{
return Largest(theRoot->rChildptr);
}
else
{
T value = theRoot->data;
delete theRoot;
return value;
}
Or simply remove the else case altogether (since you always return if the child pointer is null):
if (theRoot->rChildptr != NULL)
{
return Largest(theRoot->rChildptr);
}
T value = theRoot->data;
delete theRoot;
return value;
You will also need to make sure that the parent node does not still point to a deleted child (hard to see exactly what is going on because you haven't posted much code).
You cannot simply delete the object you don't want -- you must also remove the reference you used to find the node that you are deleting. And, if the node has any children, you must reattach the child nodes elsewhere to the tree so that they remain reachable.
The thing that makes it so tricky is that you have to properly update: the parent's reference to the node being deleted; one of the 'child' pointers for one of the children of the deleted node; and the parent links from both children of the deleted node. If you perform the updates out-of-order, you'll read a stale pointer and perhaps corrupt memory, so you must wait to remove nodes until you do not need any more references from within the node and you've removed references to the node from elsewhere.
Update
Don't forget that "the last right node" can in fact be the root of your tree:
5
4
3
2
1
5 is the largest, right-most, node of your tree, and if you delete it, you've lost your entire tree.
Unless you're doing some re-balancing that we're not seeing here; if you are, be sure you also handle this case:
2
1
Our friends at Wikipedia have been very kind to analyze how to delete a node from a binary search tree:
Deleting a leaf (node with no children): Deleting a leaf is easy, as we can simply remove it from the tree.
Deleting a node with one child: Remove the node and replace it with its child.
Deleting a node with two children: Call the node to be deleted N. Do not delete N. Instead, choose either its in-order successor node
or its in-order predecessor node, R. Replace the value of N with the
value of R, then delete R.
Your delete code must handle all three of these cases. Don't forget that the node you're deleting might be the root of the tree and not have a parent node.
Can you post the entire program so that it can be compiled. But basically the problem is that when theRoot->rChildptr is NULL you are deleting theRoot and then your return statement tries to return theRoot->data which is pointing to nowhere.
Related
I have these functions to remove a node from my binary search tree:
bool collection::removeFromTree(const char name[])
{
for (treeNode * curr = root; curr;)
{
int8_t result = strcmp(name, curr->item->getName());
if (result == 0)
{
deleteNode(curr);
return true;
}
else if (result < 0)
curr = curr->left;
else if (result > 0)
curr = curr->right;
}
return false;
}
void collection::deleteNode(treeNode *& goneNode)
{
//if it's a leaf
if (!goneNode->left && !goneNode->right)
{
delete goneNode; //node's destructor gets invoked
goneNode = nullptr;
}
//if it has right child
else if (!goneNode->left)
{
goneNode = goneNode->right;
}
//if it has left child
else if (!goneNode->right)
{
goneNode = goneNode->left;
}
//if it has both children
else
{
treeNode * prev = nullptr;
treeNode * curr = goneNode->right;
while (curr->left)
{
prev = curr;
curr = curr->left;
}
//prev points to the copy over data
delete goneNode->item;
if (!prev)
{
goneNode->item = curr->item;
goneNode->right = curr->right;
curr->item = nullptr;
}
else
{
goneNode->item = curr->item;
curr->item = nullptr;
prev->left = curr->right;
}
}
}
This runs fine, but when I try to list all the elements in my tree after deleting a node (with these functions):
void collection::displayByName() const
{
std::cout << std::endl
<< "========================================" << std::endl;
//display the tree inorder
listAll(root);
}
void collection::listAll(const treeNode * const & root) const
{
if (root)
{
std::cout << *(root->item) << std::endl
<< "========================================" << std::endl;
listAll(root->left);
listAll(root->right);
}
}
I receive this error:
And when I quit the program after deleting a node (invoking these destructors):
collection::~collection()
{
delete root;
}
collection::treeNode::~treeNode()
{
delete left;
delete right;
}
I recieve this error:
Any suggestions would be greatly appreciated because I see no reason for my listAll() function to be calling nodes that I've already deleted.
By the way, this is my struct for my treeNode:
struct treeNode
{
treeNode();
treeNode(vendor *& item);
~treeNode();
vendor * item;
treeNode *left, *right;
};
treeNode * root; //the bst
hashNode ** table; //the hash table
uint8_t capacity;
uint8_t size;
const static uint8_t INIT_CAP = 20;
When you need to remove a node from a singly linked list or a tree, I find using a pointer to pointer is handy. Namely, if we have a treeNode** ptr;, then *ptr is the pointer to our node. So, if ptr = &root, then *ptr = nullptr sets root to nullptr.
I removed the deleteNode function and threw its logic in the removeFromTree function.
bool collection::removeFromTree(const char name[])
{
treeNode** ptr = &root;
Instead of being a pointer to treeNode, ptr will point to a treeNode* inside the tree structure. This way, we can modify the pointer that led us to the current node. The lines marked //same as before have the same logic you were using, just possibly modified to account for the fact ptr has another level of dereferencing to do.
int result; //same as before
while (*ptr) //While we haven't hit a dead end
{
result = strcmp(name, (*ptr)->item->getName()); //same as before
if (result < 0) //same as before
ptr = &((*ptr)->left); //same as before
else if (result > 0) //same as before
ptr = &((*ptr)->right); //same as before
else //begin deleteNode() logic
{
if ((*ptr)->left && (*ptr)->right) //two children
{
Here, we use pointers to member because the alternative was a conditional operator on every line. If a node has two children, we need to find either the rightmost node on the left side, or the leftmost node on the right side. That's the node we can replace the current node with.
treeNode* treeNode::*dir = some_condition ? &treeNode::right : &treeNode::left; //pointer to treeNode member of type treeNode*
treeNode* treeNode::*ndir = some_condition ? &treeNode::left : &treeNode::right; //pointer to treeNode member of type treeNode*
dir now either points to left or right, which is the direction we are searching the tree for. ndir is the opposite direction. So, if we want the rightmost node on the left side, (*ptr)->*dir == (*ptr)->left and (*ptr->*ndir == (*ptr)->right. If we want the leftmost right node, it would be reversed. This is just a more complicated way to do less work, really. It shouldn't be hard to remove. some_condition is just either true or false. true means the left side of the tree (from the current node) loses a node, and false means the right side does.
treeNode** replacement = &((*ptr)->*ndir); //the node to replace the current one with
while ((*replacement)->*dir) //While we aren't at the edge
replacement = &((*replacement)->*dir);
This loops until *replacement is the node we need to replace *ptr with.
treeNode* rep_branch = (*replacement)->*ndir; //If the replacement node had a child, this is now it
(*replacement)->left = (*ptr)->left; //Copy current to replacement
(*replacement)->right = (*ptr)->right; //Copy current to replacement
(*ptr)->left = nullptr; //null out current in case of destructor
(*ptr)->right = nullptr; //null out current in case of destructor
Now, the replacement node is pointing to the node-to-be-deleted's children, and our soon to be expired node has no children anymore. Now, it's safe to delete the unwanted node. If the node class had a destructor to delete its children, the left and right pointers were set to nullptr just in case.
delete *ptr; //delete unwanted node
*ptr = *replacement; //replacement node has taken the unwanted node's place in the tree
*replacement = rep_branch; //The replacement's child takes its own place
}
This completes the tree's structure. Wherever the unwanted node was, the replacement node has taken its place. And because the replacement node was required to be an edge node, it had at most one child. We just replace it with the child.
else if ((*ptr)->left) //one child on left
{
treeNode* current = *ptr;
*ptr = (*ptr)->left; //replace current with left
current->left = nullptr; //null out for safety
delete current;
}
else if ((*ptr)->right) //one child on right
{
treeNode* current = *ptr;
*ptr = (*ptr)->right; //replace current with right
current->right = nullptr; //null out for safety
delete current;
}
else //no children
{
delete *ptr;
*ptr = nullptr;
}
return true; //yay it's over
}
}
return false; //never found it
}
The rest is fairly straightforward, just replacing easier nodes and returning. Hopefully this gives you some ideas about how to approach problems like this, and the occasional uses of some of these structures. This is what I meant about using treeNode** over treeNode* for operations like this.
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;
}
Does this look right? I mean I am trying to implement the delete function.
Node* BST::findNode(int tofind) {
Node* node = new Node;
node = root;
while (node != NULL) {
if (node->val == tofind) {
return node;
} else if (tofind < node->val) {
node = node->left;
} else {
node = node->right;
}
}
}
Here is the delete, it's not even close to done but,
void BST::Delete(int todelete) {
// bool found = false;
Node* toDelete = new Node();
toDelete=findNode(todelete);
if(toDelete->val!=NULL) {
cout << toDelete->val << endl;
}
}
This causes a segmentation fault just running that, any ideas?
The main problem with findNode() is that you never return the node that you've found. That's why you're getting the segfault.
Also, in deleteNode() you should check whether findNode() has returned NULL. And of course you also need to code up the rest of the deletion logic.
Finally, the two new Node allocations are unnecessary and are leaking memory.
oh wait it's because in delete I should have done:
if(toDelete!=NULL) {
cout << toDelete->val << endl;
}
before it was
if(toDelete->val!=NULL)
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
Ok so, I have a read method that is reading the values in correctly (all 7000), (hand written 15 values as a tree structure), doesn't create any errors.
However, when it comes to the output of the binary tree I am using the method as stated on several websites.
The error I am getting is a stack overflow, and I am assuming its due to the recursive calls and never breaking out, But I have no idea why this isn't working.
Any help is appreciated, thanks.
Code Listed Below:
// Read
void BinaryTreeStorage::read(ifstream& _fin)
{
// Get first line with number of names in it
string numberOfNamesString;
getline(_fin, numberOfNamesString);
// Loop through all the names
string line;
int num = 0;
while (!_fin.eof())
{
getline(_fin, line);
if (line != "")
{
// Insert Value Here
if (root != NULL)
{
insert(line, root);
}
else
{
insert(line);
}
}
}
}
// Write
void BinaryTreeStorage::write(ofstream& _out) const
{
inorderPrint(_out, root);
}
// inorderPrint
void BinaryTreeStorage::inorderPrint(ofstream& _out, node *_root) const
{
if (_root != NULL)
{
// Inorder
inorderPrint(_out, root->left);
_out << root->nodeValue;
cout << root->nodeValue << " ";
inorderPrint(_out, root->right);
}
}
// Insert if root is null
void BinaryTreeStorage::insert(string _nodeValueIn)
{
if(root!=NULL)
insert(_nodeValueIn, root);
else
{
root=new node;
root->nodeValue=_nodeValueIn;
root->left=NULL;
root->right=NULL;
}
}
// Insert when root is not null
void BinaryTreeStorage::insert(string _nodeValueIn, node *leaf)
{
if(_nodeValueIn< leaf->nodeValue)
{
if(leaf->left!=NULL)
insert(_nodeValueIn, leaf->left);
else
{
leaf->left=new node;
leaf->left->nodeValue=_nodeValueIn;
leaf->left->left=NULL; //Sets the left child of the child node to null
leaf->left->right=NULL; //Sets the right child of the child node to null
}
}
else if(_nodeValueIn>=leaf->nodeValue)
{
if(leaf->right!=NULL)
insert(_nodeValueIn, leaf->right);
else
{
leaf->right=new node;
leaf->right->nodeValue=_nodeValueIn;
leaf->right->left=NULL; //Sets the left child of the child node to null
leaf->right->right=NULL; //Sets the right child of the child node to null
}
}
}
You have a bug in BinaryTreeStorage::inorderPrint,
your param _root is not used where intended: You always loop on root instead.
hint: Avoid using similar names!
hint: Avoid using std to avoid bugs, unless you write std:: too often in nested templates.
hint: Do not use _ at the beginning or end of names.
hint: Do not compare with NULL: Write if(n) instead of if(n!=NULL).
hint: Do not nest blocks when not needed:
void BinaryTreeStorage::inorderPrint(std::ofstream& out, node *n) const
{
if(!n) return;
inorderPrint(out, n->left);
out << n->nodeValue; // no separator??
std::cout << n->nodeValue << " ";
inorderPrint(out, n->right);
}
void BinaryTreeStorage::inorderPrint(ofstream& _out, node *_root) const
{
if (_root != NULL)
{
// Inorder
inorderPrint(_out, root->left);
In the above code, I can see _root defined but you're using root in your call (last line above). I think that is causing the infinite loop.
When you constructed your tree nodes did you ensure that the left and right pointers are initialized to NULL?
The depth of the call tree of inorderPrint is the same as the depth of the tree itself. It looks like you don't try to keep the tree balanced, so the depth can get as large as the size of the tree.
There are a few ways of fixing this. You can make sure that the tree always remains balanced so that the depth grows logarithmically with the size of the tree. Or you can make the tree threaded, which lets you visit the nodes iteratively.