I'm trying to manage a BST in C++ for my academic purpose.
I'm not having problems anywhere except for the DeleteNode function, also
I chose to implement this data structure with a class and not with a struct.
The problem is, that I cant figure it out how to make properly work the delete function, often I got 0xDDDDDDDDD error my debugger say, sometimes I can delete the node, sometimes my program crash.
I think that's a possible problem of pointer, but I just can't figure it out where I'm doing wrong.
Here's my delete node function, the one I'm getting serious trouble about:
EDIT: The no-son delete case works perfectly, the one i'm getting mad about is the one-son-case delete.
//function that delete a selected node
void DeleteNode(TreeNode* root,int key) {
/*we got three case here:*/
//until we find the right node with value in the tree
if (root->getValue() != key && root != nullptr) {
if (root->getValue() > key) {
DeleteNode(root->Left, key);
}
else if (root->getValue() < key) {
DeleteNode(root->Right, key);
}
}
else { //when we found the right node, then operate
/* THIS WORKS PERFECTLY! */
//first case: our node got no right and left son
if (!root->Left && !root->Right) {
TreeNode* tmp = root->Father;
if (tmp->Left == root) { //if the son is a left son
tmp->Left = nullptr;
delete root;
}
else if (tmp->Right == root) { //if the son is a right son
tmp->Right = nullptr;
delete root;
}
}
//second case: our node got a left but no right son
/* THIS ONE DOESN'T WORK. */
else if (!root->Right) {
TreeNode *tmp = root;
root = root->Left; //new root is the left son of the root
root->Father = tmp->Father; //linking the father to the new son
tmp->Father->Left = root; //linking the son to the new father
delete tmp;
std::cout << "Erased!" << std::endl;
}
else if (!root->Left) {
TreeNode *tmp = root;
root = root->Right; //new root is the right son of the root
root->Father = tmp->Father; //linking the father to the new son
tmp->Father->Right = root; //linking the son to the new father
delete tmp;
std::cout << "Erased!" << std::endl;
}
}
}
I tried a lot of combination, but the result are the same every time: it crashes on the first occurrence of the InOrder display function. (and when it does not, the function just delete the first nodes and then crash when i try to delete a new one.)
Here's a simple main where i'm trying to act the delete:
int main()
{
TreeNode root;
root.insertNode(&root,50);
root.insertNode(&root,30);
root.insertNode(&root,20);
root.insertNode(&root,40);
root.insertNode(&root,70);
root.insertNode(&root,60);
root.insertNode(&root,80);
for (int i = 0; i < 5; i++) {
int n;
cin >> n;
root.DeleteNode(&root, n);
cout << "In-Order: "; root.inOrder(&root);
cout << endl;
cout << "Pre-Order: "; root.preOrder(&root);
cout << endl;
cout << "Post-Order: "; root.postOrder(&root);
cout << endl;
}
}
Here's my full BST code (except the delete one that i submitted before, just for being more complete in the understanding of my code)
class TreeNode {
private:
int value;
TreeNode* Left;
TreeNode* Right;
TreeNode* Father;
public:
//constructor
TreeNode() {
this->Right = nullptr;
this->Left = nullptr;
this->Father = nullptr;
}
TreeNode(int value) {
this->value = value;
this->Right = nullptr;
this->Left = nullptr;
this->Father = nullptr;
}
//functions
int getValue() { return value; }
void setValue(int value) { this->value = value; }
//function to create a new node and insert a value into it
TreeNode* insertNode(TreeNode* root, int value) {
if (root->getValue() == NULL) {
root->setValue(value);
root->Father = nullptr;
}
else {
if (value > root->getValue()) {
if (root->Right) {
insertNode(root->Right, value);
}
else
root->Right = new TreeNode(value);
root->Right->Father = root;
}
else if (value < root->getValue()) {
if (root->Left) {
insertNode(root->Left, value);
}
else
root->Left = new TreeNode(value);
root->Left->Father = root;
}
}
return root;
}
//function to search a value into a BST
TreeNode* SearchNode(TreeNode* root, int key) {
if (root->getValue() == key) {
return root;
}
else if (root->getValue() < key) {
if (root->Right) {
SearchNode(root->Right, key);
}
else return nullptr;
}
else if (root->getValue() > key) {
if (root->Left) {
SearchNode(root->Left, key);
}
else return nullptr;
}
}
//function that return the height of the tree
int TreeHeigth(TreeNode* root) {
int heigth;
if (root == nullptr) {
return 0;
}
else {
return heigth = 1 + max(TreeHeigth(root->Left), TreeHeigth(root->Right));
}
}
//function that returns the number of the nodes
int CountTreeNode(TreeNode* root) {
if (root == nullptr) {
return 0;
}
else {
return CountTreeNode(root->Left) + CountTreeNode(root->Right) + 1;
}
}
//function that returns the minimum values into the tree
TreeNode* MinimumNode(TreeNode* root) {
if (root == nullptr) {
return nullptr;
}
while (root->Left != nullptr) {
root = root->Left;
}
return root;
}
//function that returns the maximum value into the tree
TreeNode* MaximumNode(TreeNode* root) {
if (root == nullptr) {
return nullptr;
}
while (root->Right != nullptr) {
root = root->Right;
}
return root;
}
//function that returns a successor of a given nodeb
TreeNode* SuccessorNode(TreeNode* node) {
//first case: our node got a rigth subtree:
if (node->Right != nullptr) {
return MinimumNode(node->Right);
}
//second case: our node doesnt got a right subtree: lets get
//upper in the tree until our node isn't a left child.
TreeNode* Ancestor = node->Father;
while (Ancestor != nullptr && node == Ancestor->Right) {
node = Ancestor;
Ancestor = Ancestor->Father;
}
}
//function tht returns a predecessor of a given node
TreeNode* PredecessorNode(TreeNode* node) {
//first case: (inverse to successor) our node got a left subtree:
if (node->Left != nullptr) {
return MaximumNode(node->Left);
}
TreeNode* Ancestor;
if (node->Father == nullptr)
return nullptr;
else
Ancestor = node->Father;
while (Ancestor != nullptr && node == Ancestor->Left) {
node = Ancestor;
Ancestor = Ancestor->Father;
}
return Ancestor;
}
//function that prints information about nodes
void InfoNode(TreeNode *root) {
root != nullptr ? std::cout << "Nodo corrente: " << root->getValue() << std::endl
: std::cout << "Nodo corrente: " << "NULL" << std::endl;
root->Father != nullptr? std::cout << "Padre: " << root->Father->getValue() << std::endl
: std::cout << "Padre: " << "NULL" << std::endl;
root->Left != nullptr ? std::cout << "Figlio SX: " << root->Left->getValue() << std::endl
: std::cout << "Figlio SX: " << "NULL" << std::endl;
root->Right!= nullptr ? std::cout << "Figlio DX: " << (root->Right)->getValue() << std::endl
: std::cout << "Figlio DX: " << "NULL" << std::endl;
}
//visits of a tree
void preOrder(TreeNode* root) {
if (root != nullptr) {
std::cout << root->getValue() << " ";
preOrder(root->Left);
preOrder(root->Right);
}
}
void inOrder(TreeNode* root) {
if (root != nullptr) {
inOrder(root->Left);
std::cout << root->getValue() << " ";
inOrder(root->Right);
}
}
void postOrder(TreeNode *root) {
if (root != nullptr) {
postOrder(root->Left);
postOrder(root->Right);
std::cout << root->getValue() << " ";
}
}
//max between 2 numbers
int max(int a, int b) {
return a > b ? a : b;
}
};
And there's the representation of the tree I'm trying to work on:
50
/ \
30 70
/ \ / \
20 40 60 80
Where i'm doing it wrong?
Look at this condition: root->getValue() != key && root != nullptr, This first calls getValue and after that checks root has legal value. swap them(root != nullptr && root->getValue() != key).
Finally I think you must change last line to tmp->Father->Left = root; to fix crash problem.
TreeNode *tmp = root;
root = root->Right; //new root is the right son of the root
root->Father = tmp->Father; //linking the father to the new son
tmp->Father->Right = root; //linking the son to the new father
PS: Also do this exchange for other side...
Note: This is true until root is left child of his father otherwise your code is true. Precisely you must check if root is left child if his father do tmp->Father->Left = root; else tmp->Father->Right = root;
Note: As you mentioned your code does not handle deletion of a node with two childern.
As there is already an answer giving you directions to correct the specific errors, I will try to focus on a suggestion that will help you avoid similar error all together:
Try separating your current function into two:
One that searches a node with specific key, for example: Node* search(int key) function that returns either a pointer to the node with wanted key or nullptr, or use the one that your already have.
One that deletes (and re-wires) the node passed as pointer and returns: next, previous, etc: Node* delete(Node* n).
Then call search, test against nulltpr, and if different, pass the returned pointer as an input argument in delete.
In this way you could easily detect on which phase is you problem: searching or deleting.
P.S.: figuring out re-wiring bugs is usually done through diagrams (boxes and arrows). Decide what you should do, separate it into steps and implement it.
Well, once one know that DEBUG version use sentinel value, it become much more trivial to find problems in code.
When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete?
0xDD is for dead memory. That is memory that has been already deleted. So when the debugger stop and it tells you that you have a bad pointer and the data contains a lot of 0xDD, you know the data has already been deleted. At that point, you should inspect class that contain the data to see if they are deleted too so you know which objects were deleted when the are embedded one inside another.
Be aware that sometime you might have some data that has been changed in part of the class if some operations use delete memory. Looking at memory pattern also help finding uninitialized memory and other similar problem.
Some other links:
Why does the not allocated memory is marked like 0xCC?
https://msdn.microsoft.com/en-us/library/974tc9t1.aspx
https://www.codeguru.com/cpp/w-p/win32/tutorials/article.php/c9535/Inside-CRT-Debug-Heap-Management.htm
http://www.nobugs.org/developer/win32/debug_crt_heap.html
In a case like yours, if you follow the good practice of writing unit tests, then it would even be more trivial to find the problem. In fact, if you do proper testing, then you will test all possible cases so you will know which cases fail and it would help you find where you might do something wrong.
I would like to add something to the answer of #Bonje Fir.
Sure it is a correct answer, but partially: I'll explain why.
He suggested to swap the last piece of code i wrote:
Case: we're in the right subtree, and we would like to erase 70 (because we don't have anymore the leaf node 60):
50
/ \
30 70
/ \ \
20 40 80
now, with the code that #Bonje Fir suggested us, we would got a problem here:
TreeNode *tmp = root;
root = root->Right; //new root is the right son of the root
root->Father = tmp->Father; //linking the father to the new son
tmp->Father->Left (instead of Right) = root; //linking the son to the new father
Because the code is saying, that once you updated the new root with his son, link the father of the previous root (that we saved in a tmp variable) with his left son. Then we would assist to something like this:
50
/ x
80 80
/ \
20 40
and that's inconsistent.
Now take a look on the other side, with the same code and without leaf node 20:
50
/ \
30 70
\ / \
40 60 80
the code fit here, because we're in the right subtree.
so once update 30 with 40 (root = root -> right) the situation would be this:
50
x \
40 70
/ \
60 80
then the piece of code #Bonje Fir wrote us, would fit perfectly:
tmp->Father->Left = root
because for sure, we're assigning 40 to the left son of the father of the original root. (because we're in the left subtree.)
50
/ \
40 70
/ \
60 80
So i made a little change to correct this logic problem, and make it work both in the right and left subtree.
else if (!root->Left) {
TreeNode *tmp = root;
root = tmp->Right;
root->Father = tmp->Father; //linking the father to the new son
//we need also to connect the son with the father, but first
//we need to know in which subtree we're in.
if (root->Father->Right == tmp) //if we're in the right subtree
tmp->Father->Right = root;
else ////if we're in the left subtree
tmp->Father->Left = root;
delete tmp;
std::cout << "Erased!" << std::endl;
}
i took advantage of the fact i didnt erase my root, once assigned the new one, so the father of the root still points to the old root.
(same speech for the opposite case.)
Related
I was experimenting a little bit with C++ and decided to try and create whole tree deletion method for Binary Tree. For some reason I keep getting pointer error because pointer is 0xDDDDDDDD.
If someone can explain me why it does not work I would appreciate it so I can learn more about pointers.
struct Node {
Node* parent;
Node *left,
*right;
int value;
inline Node() : parent(nullptr), left(nullptr), right(nullptr), value(0){}
~Node() = default;
};
class BST {
public:
Node* root;
public:
BST() = default;
inline BST(int i)
{
root = new Node();
root->value = i;
root->parent = nullptr;
root->left = nullptr;
root->right = nullptr;
}
BST(const BST& bst) = default;
void Insert(int i);
void DeleteAll(Node* node);
};
#include <iostream>
int main()
{
BST t(20);
t.root->left = new Node();
t.root->left->value = 22;
t.root->left->parent = t.root;
t.root->right = new Node();
t.root->right->value = 15;
t.root->right->parent = t.root;
t.DeleteAll(t.root);
}
void BST::Insert(int i)
{
}
void BST::DeleteAll(Node* node)
{
Node* target = node;
std::cout << "Probing node with value " << node->value << std::endl;
if (node->left == nullptr && node->right == nullptr)
{
target = node->parent;
std::cout << "Node deleted with value: " << node->value << std::endl;
delete node;
if (target == nullptr)
{
std::cout << "Found and deleted root!" << std::endl;
return;
}
std::cout << "Parents node value: " << target->value << std::endl;
}
else if (node->left != nullptr)
{
std::cout << "Found left ptr with value: " << node->left->value << std::endl;
target = node->left;
}
else if(node->right != nullptr)
{
std::cout << "Found right ptr with value: " << node->right->value << std::endl;
target = node->right;
}
DeleteAll(target);
}
The prompt from the console I am getting is:
Probing node with value 20
Found left ptr with value: 22
Probing node with value 22
Node deleted with value: 22
Parents node value: 20
Probing node with value 20
Found left ptr with value: -572662307
Probing node with value -572662307
In DeleteAll() function when it gets back to parent node to search if there is any children that is not null it always finds the left child which I deleted before. Shouldn't it be null?
And there it crashes. I have no idea why is it doing that but something is probably in the delete function. This is not a homework of any kind I am just trying to learn why this does not work.
When I run your code I get this output, and it throws "read access violation":
Found left ptr with value: -572662307
-572662307 is same as 0xDDDDDDDD This is specific for Visual Studio in debug mode. Sometimes you may not get this value.
The problem is you never allocated memory for parent (which you don't even need, more on that later) then you try to delete it over and over.
You should rewrite you code like this to understand it better:
void DeleteAll(Node* node)
{
printf("node: %p\n", node);
Node* target = node;
if (!node->left && !node->right)
{
target = node->parent; //this was never allocated, supposed to be NULL
delete node;
if (target == nullptr) //target is now undefined, not NULL, can't be tested
return; //we may not get here
}
else if (node->left != nullptr)
target = node->left;
else if (node->right != nullptr)
target = node->right;
DeleteAll(target); //could be deleting the same thing again
}
The output is something like this, with different numbers:
node: 012C5078
node: 012D2F00
node: 012C5078
node: 012D2F00
node: DDDDDDDD
You see the same values repeated, it's trying to delete twice. The correct DeleteAll function is just this:
void BST::DeleteAll(Node* node)
{
if (!node)
return;
DeleteAll(node->left);
DeleteAll(node->right);
delete node;
}
You will also need a different Delete(Node* node, int value) function which deletes based on value,left,right, this will be used once you properly insert items, and you want to remove some values before BST is destroyed.
Try this example instead:
https://gist.github.com/harish-r/a7df7ce576dda35c9660
I have a left child right sibling as below:
10
* |
* 2 -> 3 -> 4 -> 5
* | |
* 6 7 -> 8 -> 9 */
I want to traverse from root to the last node, the traversal function is as below:
void traverseTree(Node * root)
{
if (root == NULL)
return;
while (root)
{
cout << " " << root->data;
if (root->child)
traverseTree(root->child);
root = root->next;
}
}
As I understood, if the node has a child, then the pointer points to its child, otherwise points to the sibling (next). In this case, when the pointer points to element 6, it will go to the root->next element (which is NULL). However, the function can still be able to print the remaining element (5,7,8,9). Can any one help me explain how traverseTree works?
Here's the code to recreate the tree:
// CPP program to create a tree with left child
// right sibling representation.
#include<bits/stdc++.h>
using namespace std;
struct Node
{
int data;
struct Node *next;
struct Node *child;
};
// Creating new Node
Node* newNode(int data)
{
Node *newNode = new Node;
newNode->next = newNode->child = NULL;
newNode->data = data;
return newNode;
}
// Adds a sibling to a list with starting with n
Node *addSibling(Node *n, int data)
{
if (n == NULL)
return NULL;
while (n->next)
n = n->next;
return (n->next = newNode(data));
}
// Add child Node to a Node
Node *addChild(Node * n, int data)
{
if (n == NULL)
return NULL;
// Check if child list is not empty.
if (n->child)
return addSibling(n->child, data);
else
return (n->child = newNode(data));
}
// Traverses tree in level order
void traverseTree(Node * root)
{
if (root == NULL)
return;
while (root)
{
cout << " " << root->data;
if (root->child)
traverseTree(root->child);
root = root->next;
}
}
//Driver code
int main()
{
Node *root = newNode(10);
Node *n1 = addChild(root, 2);
Node *n2 = addChild(root, 3);
Node *n3 = addChild(root, 4);
Node *n4 = addChild(n3, 6);
Node *n5 = addChild(root, 5);
Node *n6 = addChild(n5, 7);
Node *n7 = addChild(n5, 8);
Node *n8 = addChild(n5, 9);
traverseTree(root);
return 0;
}
After executing traverseTree(root->child) the control flow will continue from the next line. You're not returning from the function, just calling another function from within this function.
void traverseTree(Node * root)
{
if (root == NULL)
return;
while (root)
{
cout << " " << root->data;
if (root->child)
traverseTree(root->child); // First, if child exists, traverse child. No return statement following here.
root = root->next; // Next, traverse sibling
}
}
If you still have doubts it would do you good to read about the program flow when calling a function.
Update(completely irrelevant to the question): As requested by OP, solution using stack:
void traverseTree(Node * root)
{
if (root == NULL)
return;
stack<Node*> s;
s.push(root);
while (!s.empty())
{
Node* top = s.top();
cout << " " << top->data;
s.pop();
if (top->next) s.push(top->next);
if (top->child) s.push(top->child);
}
}
struct node
{
int data;
node *left,*right;
};
class bst
{
public:
node *root;
bst(){root = NULL;}
void bst_insert(node*,int);
void inorder(node*);
};
void bst::bst_insert(node* x, int d) {
if (x== NULL) {
node* tmp = new node;
tmp->data = d;
tmp->left = NULL;
tmp->right = NULL;
x= tmp;
}
else if (d <= x->data)
bst_insert(x->left,d);
else
bst_insert(x->right,d);
}
void bst::inorder(node* x) {
if(x != NULL) {
inorder(x->left);
cout << x->data << " ";
inorder(x->right);
}
}
int main() {
bst b;
b.bst_insert(b.root,3);
b.bst_insert(b.root,2);
b.inorder(b.root);
}
bst is a class with member node* root (initialize with null on constructor)
Binary Search Tree display in order always shows empty.
What is wrong with the code ?
the code seems fine, but always bst has no value and always show empty, and root is null !!!
No code anywhere sets root to anything other than NULL. When you call inorder, it does nothing since root is NULL.
b.bst_insert(b.root,3);
Since root is NULL at first, this is equivalent to:
b.bst_insert(NULL,3);
This doesn't attach the newly-created node to anything.
I'm currently writing a program that will delete a node from a binary search tree (among other things, but the deletion is my issue) and I'm having a problem with the final step of deletion, specifically the final step of deleting a node with 2 children.
The way that I'm deleting is the way described here.
I take the farthest down left child-node (if on the right side of root) or the farthest down right child-node (if on the left) and replace the value of the node I want to delete with that value, then delete the node I just copied from.
I have all the steps complete except deleting the node I copied from; for some reason my code does not properly delete it and creates a random number value as well as a random parent value for the node I just tried to delete. I believe this is caused by an unrepaired link in the tree somewhere but being a non-experienced programmer, I cannot find it. Hopefully someone more well versed in BSTs can help me.
Here is my code (I only included code that influences the deletion function, I didn't think it necessary to include things that come after such as the destroy function):
#include <iostream>
using namespace std;
struct node
{
int data; //Stores data within the trees pointers
node * parent; //Used to move up in the tree
node * left; //Used to move left in the tree
node * right; //Used to move right in the tree
};
node * create (int data, node **tree); //Function to insert elements into the tree
void printTree (node * tree); //Function to print the tree
node *search(int key, node *tree); //Function to find data in the tree
node * delNode (node * tree, node * root); //Function to delete data from the tree
node * findSmallestRight (node * tree, node **smallest);
node * findLargestLeft (node * tree, node **smallest);
int main()
{
node * root = NULL; //Root will be the first element in the tree
node * current = NULL; //Return value for insert function to keep changes
int value; //Value entered by user
while (true) //Loop to fill tree with data
{
cout << "Enter an integer, 0 to quit" << endl;
cin >> value;
if (value == 0) //Quit when 0 is entered, BEFORE entering it into the tree
break;
current = create(value, &root); //Insert value into the tree
cout << "After inserting " << value << " tree is:" << endl;
printTree(root); //Print the tree
}
while (true) //Loop to delete data from tree
{
cout << "Search for a value to delete from the tree, 0 to quit" << endl;
cin >> value;
if (value == 0)
break;
current = search(value, root); //Find the value in the tree
if (current == NULL)
cout << value << " is not in tree. Could not delete." << endl;
else
{
root = delNode(current, root); //Delete the data
cout << value << " has been deleted. The tree is now:" << endl;
printTree(root); //print the tree
}
}
destroy(root); //Destroy the tree
return 0;
}
void printNode (node * Node) //Function to print a node in the tree
{
cout << "addr= " << Node << " parent= " << Node->parent << " left= " << Node->left << " right= " << Node->right << " data= " << Node->data << endl;
}
node * createNode (int data) //Function to create a new node in the tree
{
node * newNode = NULL; //Create a new pointer
newNode = new node; //Make that pointer a node
newNode->data = data; //Fill it with data
newNode->left = NULL; //Make it point left to NULL
newNode->right = NULL; //and right to NULL
return newNode;
}
node * create (int data, node **tree) //Function to insert elements into the tree
{
node * newNode = NULL; //Create a new pointer
if ((*tree) == NULL) //Check if tree exists already
{
//If it doesn't, create a new node and make it the root
newNode = createNode(data);
*tree = newNode;
(*tree)->parent = NULL; //Root has a parent of NULL
}
else if (data < (*tree)->data) //If the data is smaller than root, insert on the left
{
if ((*tree)->left == NULL)//If there is no node on the left, create a new one and point to it
{
newNode = createNode(data);
(*tree)->left = newNode;
newNode->parent = *tree;
}
else
{
newNode = create(data, &((*tree)->left));//If there is a node on the left, repeat function until there isn't
}
}
else //If the data is greater than or equal to root, insert on the right
{
if ((*tree)->right == NULL)
{
newNode = createNode (data); //If there is no node on the right, create a new one and point to it
(*tree)->right = newNode;
newNode->parent = *tree;
}
else
{
newNode = create(data, &((*tree)->right)); //If there is a node on the right, repeat function until there isn't
}
}
return newNode; //Return the new node to keep the changes to the value
}
void printTree (node * tree) //Function to print the tree
{
if (tree != NULL) //Check if tree actually existsreturn root;
{
//Recursively print the left side, then the root, then the right side
printTree(tree->left);
printNode(tree);
printTree(tree->right);
}
}
node *search(int key, node *tree) //Function to find data in the tree
{
if (tree == NULL || tree -> data == key)
{
return tree; //If the data either does not exist or has been found, return
}
if (key < tree->data)
{
return search(key, tree->left); //If the data is less than the current data, keep checking the left
}
else
{
return search(key, tree->right); //If the data is more than the current data, keep checking the right
}
}
node * delNode (node * tree, node * root)
{
node * parent; //Node for quick-reference and manipulation of tree's parent
if (tree->parent != NULL) //If tree value is not root assign a parent (root has parent of NULL so assigning would crash)
{
parent = tree->parent;
}
node * curr = tree;
//Removing node with 2 children on right
//There would also be cases for no children, 1 child, and 2 children on left but I did not include them as the two former are done and the latter can be copied once this is solved :)
else if (tree->left != NULL && tree->right != NULL && parent->right == tree && parent != NULL)
{
node * smallest; //Node to find smallest data value on left side
//Initialise and make it point to nothing
smallest = new node;
smallest->left = NULL;
smallest->right = NULL;
smallest->parent = NULL;
node * nReplace = NULL; //Node to replace data in tree
//Initialise and make it point to nothing
nReplace = new node;
nReplace->left = NULL;
nReplace->right = NULL;
nReplace->parent = NULL;
nReplace = findSmallestRight(tree, &smallest); //Function to find smallest data value on right side
tree->data = nReplace->data; //Replace tree's data with the new data
cout << nReplace << " " << nReplace->data << endl; //Debugging code
delete nReplace; //Delete nReplace
cout << nReplace << " " << nReplace->data << endl; //Debugging code
}
return root; //Return root to keep changes in tree
}
node * findSmallestRight (node * tree, node **smallest) //Function to find smallest data value on right side
{
node * parent = tree->parent; //Node for easy manipulation of tree's parent
//Check if current value is a potential candidate for smallest
if (tree->left == NULL && tree->right == NULL && parent->left == tree)
{
*smallest = tree; //If it is, make smallest equal to it
}
if (tree->left == NULL && tree->right != NULL) //Check if the are only branches on the right
{
findSmallestRight (tree->right, smallest); //Recurse through the right
}
else if (tree->left != NULL && tree->right == NULL) //Check if there are only branches on the left
{
findSmallestRight (tree->left, smallest); //Recurse through the left
}
else if (tree->left == NULL && tree->right == NULL) //Check if there are no branches on both sides
{
return *smallest; //Return the smallest
}
else
{
//If there are branches on both sides recurse through both
findSmallestRight (tree->left, smallest);
findSmallestRight (tree->right, smallest);
}
return *smallest; //Return the smallest
}
I think your findSmallestRight() is all messed up from recursion to returning the values.
You just have to find the SMALLEST element on the Right subtree i.e for the right child go on iterating it's Left children until last one, that'll be minimum one.
Code is as simple as : (First see picture for name associations)
if (current->left != NULL && current->right != NULL) //condition if you Current Node (to be deleted) has 2 Children
{ if((current->right)->left!=NULL) //If Right Child has left child go till last leftmost child.
{
Node* leftCurrent;
Node* leftCurrentPred;
leftCurrentPred=current->right;
leftCurrent=(current->right)->left;
while(leftCurrent->left != NULL)
{
leftCurrentPred=leftCurrent;
leftCurrent=leftCurrent->left;
}
current->data=leftCurrent->data;
delNode(leftCurrent, root); //Delete leftCurrent node i.e node with no child
leftCurrentPred->left=NULL;
cout<<item<<" has been removed from the Tree."<<endl;
}
else
{ //If Right Child of current doesn't has Left child it is itself smallest one.
Node* temp=current->right;
current->data=temp->data;
current->right=temp->right;
delNode(temp,root); //Delete temp node i.e node with no child
cout<<item<<" has been removed from the Tree."<<endl;
}
}
I was trying to implement a simple Binary Search Tree for practice. I tried to just add values and print the values in the nodes. However, I am not getting the proper ascending order of values in the nodes. Here is what I have:
struct Node
{
int data;
Node* leftN;
Node* rightN;
};
typedef Node* Node_ptr;
Node_ptr head;
//INSERT_VALUE FUNCTION
Node* insert_value(Node_ptr leaf, int key)
{
//Root case when there is no set value yet
if(leaf == NULL)
{
leaf = new Node;
head = leaf;
cout << "Make the first node" << endl;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
//Left child Node
if(key < leaf->data)
{
//Search for a spot in the tree to add a Node (left value < root value < right value)
//This is only true for the left child Node
if(leaf->leftN != NULL)
insert_value(leaf, key);
//We have found a spot in the tree to add a new Node and add the value of key
else
{
cout << "Insert-left" << endl;
leaf->leftN = new Node;
leaf = leaf->leftN;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
}
//Right child Node
else if(key >= leaf->data)
{
//Search for a spot to add a new Node in the tree (only amongst the right child Nodes)
if(leaf->rightN != NULL)
insert_value(leaf, key);
//Once we have found a spot to add a new Node, append the new Node
else
{
cout << "Insert-right" << endl;
leaf->rightN = new Node;
leaf = leaf->rightN;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
}
}
//PRINT FUNCTION
void printTree(Node_ptr leaf)
{
if(leaf == NULL)
return;
printTree(leaf->leftN);
cout << "Data element: " << leaf->data << endl;
printTree(leaf->rightN);
}
//MAIN
int main()
{
Node_ptr root = NULL;
int i;
//initialize values
for(i = 1; i < 12; i+=2)
root = insert_value(root, i);
root = head;
for(i = 0; i < 11; i+=2)
root = insert_value(root, i);
root = head;
printTree(root);
root = head;
cout << "Head Node: " << root->data << endl;
return 0;
}
When I printed the results, this is what I got:
0, 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11 and the value of the head node is 1
Because you are calling the insertion as:
root = insert_value(root, i);
the location at which you insert is always using a subtree starting at the last insertion. Except the time that you re-start to add the odd numbers, when you start inserting at the head.
If you create a class BinarySearchTree that contains a head pointer, and an insert method taking an int value that calls Node::insert( head, value ), then you can just call insert on that class, without passing it a node, and it can always see to it that the insertions use the root of the tree for the start of the recursion.
Just me, but I would have a constructor for Node that takes an int and initializes the pointers to NULL. That way you don't have to do that in the insert method.
In the leaf->node? != NULL case, I think instead of calling
insert_value(leaf, key);
you want to say
leaf->node? = insert_value(leaf->node?, key)
where ? is either L or R, of course.
Something you might consider is adding a comment to the method like so:
// Adds the given key to the (sub-)tree rooted at node* then returns the new root
// of that (sub-)tree.
node *insert_value_and_return_root(node *root, int value) { ... }