The function to delete a node in a BST with the given key is as follows:
struct node* deleteNode(struct node* root, int key)
{
// base case
if (root == NULL) return root;
// If the key to be deleted is smaller than the root's key,
// then it lies in left subtree
if (key < root->key)
root->left = deleteNode(root->left, key);
// If the key to be deleted is greater than the root's key,
// then it lies in right subtree
else if (key > root->key)
root->right = deleteNode(root->right, key);
// if key is same as root's key, then This is the node
// to be deleted
else
{
// node with only one child or no child
if (root->left == NULL)
{
struct node *temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL)
{
struct node *temp = root->left;
free(root);
return temp;
}
// node with two children: Get the inorder successor (smallest
// in the right subtree)
struct node* temp = minValueNode(root->right);
// Copy the inorder successor's content to this node
root->key = temp->key;
// Delete the inorder successor
root->right = deleteNode(root->right, temp->key);
}
return root;
}
Considering the tree having the preorder traversal as: 50 30 20 40 70 60 80
I wish to delete the node 20. The function calls are as follows:
deleteNode(root=50, 20)
deleteNode(root=30, 20)
deleteNode(root=20, 20)
When it reaches this call (deleteNode(20, 20)), the else part is executed. Since root->left == NULL, the code snipped is executed as:
temp = root->right (which is NULL)
free (root)
return temp (returning NULL)
It is returned to the last call root->left = deleteNode(20, 20) = NULL. What happens to the other calls (i.e. deleteNode(30, 20) and deleteNode(50, 20)) and at the end of the execution the root is returned. Which of the roots are actually returned?
To answer "which of the roots is actually returned" ... they all are. The question is where are they returned to and what is the final value.
When you traced forwards through your code you saw where the recursive function call was executed and understood that you created a new copy of the function with different values and traced your way from the top again. You are now unwinding that process.
Following from where you left off, you return temp whose value is NULL to the function call for root->left = deletenode(20, 20) as you realized. You now resume execution from that point. The else if and else conditions are not magically re-evaluated, you drop to return root whose left node was set to NULL. This root is then returned to deletenode(30,20) and the left or right portion is then replaced with the returned value.
This pattern continues until all the function calls have resolved. The name root may be confusing but it is the "root" of each sub-tree created during the recursion which only form branches of the original tree.
To provide some illustration, using your values:
50 <- root for deletenode("node 50", x)
/ \
30 70 <- root for deletenode("node 50"-> left or right, x)
/ \ / \
20 40 60 80 <- root for deletenote("node 50"->left/right->left/right,x)
An attempt at a trace for you:
deleteNode( "node 50", 20 )
if ( root == NULL) is false, skip statement (let's call root "node 50")
if ( 20 < 50 ) is true so execute "node 50"->left = deleteNode( "node 50"->left, 20 )
if ( root == NULL ) is false, skip statement (root here is now "node 50"->left, or "node 30")
if ( 20 < 30 ) is true so execute "node 30"->left = deleteNode( "node 30"->left, 20)
if ( root == NULL) is false, skip statement (root is "node 20")
if ( 20 < 20 ) is false, skip block
else if ( 20 > 20 ) is false, skip block
else block:
if ( "node 20"->left == NULL ) is true
create a temp node with the right child of "node 20" (happens to be NULL)
delete "node 20"
return the address of the temp node
assign the returned value (NULL) to "node 30"->left
control flow bypasses the rest of the if structure, execute return "node 30"
"node 30" was returned, assign the value to "node 50"->left
control flow bypasses the rest of the if structure, execute return "node 50"
End of trace.
Your returned tree now looks something like:
50 <- root for deletenode("node 50", x)
/ \
30 70 <- root for deletenode("node 50"-> left or right, x)
/ \ / \
NULL 40 60 80 <- root for deletenote("node 50"->left/right->left/right,x)
I believe the "trick" to understanding recursive functions is to first understand non-recursive functions and then realise that recursive functions work exactly the same.
Imagine that you have one function for each level of the tree - deleteNode_1, deleteNode_2, deleteNode_3, and so on.
You would make your first call by passing the root of your tree to deleteNode_1.
If the node to be deleted is in a subtree of its parameter, deleteNode_1 calls deleteNode_2 with that subtree and replaces one of its parameter's subtrees with the result.
The call to deleteNode_2 might call deleteNode_3, and so on, but deleteNode_1 doesn't need to care about that, it only cares about getting a suitable subtree back from deleteNode_2.
They would look like this:
// Delete a node when 'current' is at level 1
struct node* deleteNode_1(struct node* current, int key);
// Delete a node when 'current' is at level 2
struct node* deleteNode_2(struct node* current, int key);
// Delete a node when 'current' is at level 3
struct node* deleteNode_3(struct node* current, int key);
// .. and so on, as many as you need.
and be implemented like this:
struct node* deleteNode_1(struct node* current, int key)
{
if (current == NULL) return current;
if (key < current->key)
current->left = deleteNode_2(current->left, key);
else if (key > current->key)
current->right = deleteNode_2(current->right, key);
else
{
if (current->left == NULL)
{
struct node *temp = current->right;
free(current);
return temp;
}
else if (current->right == NULL)
{
struct node *temp = current->left;
free(current);
return temp;
}
struct node* temp = minValueNode(current->right);
current->key = temp->key;
current->right = deleteNode_2(current->right, temp->key);
}
return current;
}
struct node* deleteNode_2(struct node* current, int key)
{
if (current == NULL) return current;
if (key < current->key)
current->left = deleteNode_3(current->left, key);
else if (key > current->key)
current->right = deleteNode_3(current->right, key);
else
{
if (current->left == NULL)
{
struct node *temp = current->right;
free(current);
return temp;
}
else if (current->right == NULL)
{
struct node *temp = current->left;
free(current);
return temp;
}
struct node* temp = minValueNode(current->right);
current->key = temp->key;
current->right = deleteNode_3(current->right, temp->key);
}
return current;
}
// ...
If you understand how these functions work, the step is very small to understanding the recursive function.
Related
I am trying to write a recursive function that, given the root of a binary tree and a key, searches for the key using in-order traversal. The function returns NULL if the node with the key isn't found; otherwise it returns the node containing the key.
What I'm having trouble with is returning the node that contains the key. Every time I call the function and the key is in the binary tree, the function returns NULL. It feels like the result keeps getting overwritten by the initialization in the first line in the function.
Here's the in-order search function:
typedef struct treeNode
{
int data;
struct treeNode *left, *right;
} TreeNode, *TreeNodePtr;
typedef struct
{
TreeNodePtr root;
} BinaryTree;
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
TreeNodePtr node = NULL;
if (root != NULL)
{
node = inOrderKey(root->left, key);
if(key == root->data)
{
node = root;
return node;
}
node = inOrderKey(root->right, key);
}
return node;
}
Here's the main function:
int main()
{
FILE * in = fopen("numbst.txt", "r");
BinaryTree bst;
bst.root = NULL;
int num;
fscanf(in, "%d", &num);
while (num != 0)
{
if (bst.root == NULL)
bst.root = newTreeNode(num);
else
{
TreeNodePtr node = findOrInsert(bst, num);
}
fscanf(in, "%d", &num);
}
printf("\nThe in-order traversal is: ");
inOrder(bst.root);
printf("\nThe pre-order traversal is: ");
preOrder(bst.root);
TreeNodePtr keyNode;
int count = 0;
keyNode = inOrderKey(bst.root, 9);
if (keyNode != NULL)
count = 1;
else
count = 0;
if (count == 1)
printf("\n\n%d exists in the binary tree. In order traversal was used.\n", 9);
else
printf("\n\n%d doesn't exist in the binary tree. In order traversal was used.\n", 9);
return 0;
}
The in-order traversal of the binary tree I'm working with is: 1 2 3 4 5 7 9 21
The pre-order traversal of the binary tree is: 4 1 2 3 7 5 21 9
I'm testing the function using 9 and 31.
This code:
node = inOrderKey(root->left, key);
if(key == root->data)
{
node = root;
return node;
}
node = inOrderKey(root->right, key);
first uses inOrderKey to search the left subtree. Then it ignores the result.
Then it tests whether the current node contains the key. If it does, it returns to its caller. If the caller was itself (this is in a recursive call, not the original), the caller likely ignores the result.
Then it uses inOrderKey to search the right tree. Then it returns the result.]
Ultimately, the node containing the key will be returned only if it was in the rightmost path. If it is in the left subtree of any node, it will be ignored.
To fix this, after each call to inOrderKey, test whether the returned value is a null pointer. If it is not, return it immediately instead of going on.
The problem you have is that you insist in navigating the whole tree without checking if you found the key already. In
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
/* don't declare a local you don't know
* yet if you are going to use */
/* better to check the opposite */
if (root == NULL)
return NULL; /* no tree, nothing can be found */
TreeNodePtr node = inOrderKey(root->left, key);
if (node) return node; /* we found it in the left child */
if(key == root->data) { /* check here */
/* you found it in this node */
return root;
}
/* last chance, right child :) */
return inOrderKey(root->right, key);
}
the verifications are made, so this should work (I've not tested it, as you didn't post a complete and verifiable example, my apologies for that)
[edited - updated to use in order traversal]
Traverse left. If key not found, then check root, if key doesn't match, then recurse right.
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
TreeNodePtr node = NULL;
if (root)
{
node = inOrderKey(root->left, key);
if (node) {
return node;
}
if (key == root->data)
{
return root;
}
node = inOrderKey(root->right, key);
}
return node;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm working on a C program that scans and stores students' records in the following format into a binary search tree. For the BST I've defined:
struct student
int id
char firstname[20]
char lastname[20]
float score
char zipcode[10]
struct node
struct student data
struct node* leftChild
struct node* rightChild
One of the functions of the program should be able to delete records from the tree. The program asks the user for the last name of the student that will be deleted.
The following is the method to traverse the BST to find the target last name to be deleted:
void traverse(node* root, student data)
if(root != NULL)
traverse(root->leftChild,data)
if(strcmp(root->data.lastname,data.lastname) == 0)
root = delete(root,data)
traverse(root->rightChild,data)
Sample student structure passed to traverse function is:
struct student John
int id = 1000
char firstname = John
char lastname = Adams
float score = 90.00
char zipcode = 92121
The delete function I'm using along with the findmin because I'm aware that I need to find the minimum in the right sub-tree of the root (target node) in order to replace the target node with it:
struct node* findmin(struct node* root)
while(root->leftChild != NULL)
root = root->leftChild
return root
struct node* delete(node* root, student data)
if(root == NULL) // check if empty tree
return root
// traverse towards left if ID is less
else if(data.iD < root->data.iD)
root->leftChild = delete(root->leftChild,data)
// towards right if greater than ID
else if(data.iD > root->data.iD)
root->rightChild = delete(root->rightChild,data)
/* else would mean target last name found */
else
/* if found node has no child */
if(root->leftChild == NULL && root->rightChild == NULL)
free(root)
root = NULL
// 1 child
else if(root->leftChild == NULL) // if left child is NULL
struct node* temp = root
root = root->rightChild
free(temp)
temp = NULL
else if(root->rightChild == NULL) // if right child is NULL
struct node* temp = root
root = root->leftChild
free(temp)
temp = NULL
// 2 children
else
struct node* temp = findmin(root->rightChild)
root->data = temp->data
root->rightChild = delete(root->rightChild,temp->data)
return root;
What I would expect to happen here is that student John will be passed into traverse along with the global root of BST and when printing the BST, student John will be deleted and no longer there. However, when I pass student containing a target last name, the name will still be existing in the tree. Furthermore, when I test my code and pass a record to delete, occasionally, the program will delete not the targeted node but the node with the greatest student ID (the node furthest right in the tree) and/or will greet me with a segmentation fault 11. Is there a flaw in the code I am not seeing? Let me know if you need me to provide any further information to help you help me.
There is a first problem with the traverse function. When you delete a node, you need to update the pointer to it. You don't keep track of it.
Here are the traverse and delete functions using the pointer to node pointer strategy. As you see the code becomes simpler.
In this code pRoot is a pointer to the root pointer. You can then update it's value. You can set it to NULL or to another node due to the deletion.
void traverse(node** pRoot, student data){
if(*pRoot != NULL) {
traverse(&((*pRoot)->leftChild),data);
if(strcmp((*pRoot)->data.lastname,data.lastname) == 0)
delete(pRoot,data);
traverse(&((*pRoot)->rightChild),data);
}
void delete(node* pRoot, student data)
if(*pRoot == NULL)
return;
node *temp = *pRoot;
if((*pRoot)->leftChild == NULL)
*pRoot = (*pRoot)->rightChild;
else if((*pRoot)->rightChild == NULL){
*pRoot = (*pRoot)->leftChild;
else {
// both children are not NULL :
// we replace *pRoot with the node with
// min ID detached from the rightChild.
// find node with min ID in right child
node **pNode = &((*pRoot)->rightChild);
while((*pNode)->leftChild != NULL)
pNode = &((*pNode)->leftChild);
// *pNode is the node with minID
// its left child is NULL,
// but its right child may not be NULL
// we detach the node with min ID
node *nNode = *pNode;
*pNode = nNode->rightChild;
//replace *pRoot with *nNode
nNode->rightChild = (*pRoot)->rightChild;
nNode->leftChild = (*pRoot)->leftChild;
*pRoot = nNode;
}
free(temp);
}
Combining the above traverse and delete functions into one function, you get
void delete(node** pRoot, student *data){
if(*pRoot == NULL)
return;
delete(&((*pRoot)->leftChild), data);
detele(&((*pRoot)->rightChild), data);
if(strcmp((*pRoot)->data.lastname,data->lastname) != 0)
return;
// we delete *pRoot
node *temp = *pRoot;
if((*pRoot)->leftChild == NULL)
*pRoot = (*pRoot)->rightChild;
else if((*pRoot)->rightChild == NULL){
*pRoot = (*pRoot)->leftChild;
else {
// both children are not NULL :
// we replace *pRoot with the node with
// min ID detached from the rightChild.
// find node with min ID in right child
node **pNode = &((*pRoot)->rightChild);
while((*pNode)->leftChild != NULL)
pNode = &((*pNode)->leftChild);
// *pNode is the node with minID
// its left child is NULL,
// but its right child may not be NULL
// we detach the node with min ID
node *nNode = *pNode;
*pNode = nNode->rightChild;
//replace *pRoot with *nNode
nNode->rightChild = (*pRoot)->rightChild;
nNode->leftChild = (*pRoot)->leftChild;
*pRoot = nNode;
}
free(temp);
}
Is there any way to insert a new node in a binary tree (not bst) without comparing key values? The following code only works for the very first three nodes.
node *insert (node *root, int *key) {
if (root==NULL) {
root=newNode(root, key);
return root;
}
else if (root->left == NULL)
root->left=insert(root->left,key);
else if (root-> right == NULL)
root->right=insert(root->right,key);
return root;
}
If you change
else if (root-> right == NULL)
to just
else
Then it would have the effect of always adding to the right.
If you want it to randomly pick, add a call to srand outside this function.
srand(time(NULL));
Then in this function, call
else if (rand() > MAX_RAND / 2) {
root->right = insert(root->right, key);
} else {
root->left = insert(root->left, key);
}
at the end of your existing if/else structure.
See also:
Lack of randomness in C rand()
If your tree tracks its height at each node, you could add after your null checks something like
else if (root->left->height <= root->right->height) {
root->left = insert(root->left, key);
} else {
root->right = insert(root->right, key);
}
That would keep the tree balanced automatically. But it requires additional code to manage the height. E.g.
root->height = 1 + ((root->left->height > root->right->height) ? root->left->height : root->right->height);
I leave it up to you whether that additional overhead is worth it.
The people suggesting using a heap are suggesting using the indexes as the ordering. This is kind of useless as a heap, but it would make a balanced binary tree. So the root node would be the first inserted and the most recent inserted would be the rightmost leaf.
You could just keep track of the height of each node, and always insert it into the side with fewer children:
node *insert (node *root, int *key) {
if (root==NULL) {
root=newNode(root, key);
root->height = 0
}
else if (root->left == NULL) {
insert(root->left,key);
}
else if (root->right == NULL) {
insert(root->right,key);
}
else if (root->left->height <= root->right->height) {
insert(root->left,key);
} else {
insert(root->right,key);
}
root->height++
}
Comparing values is actually irrelevant, the only think you need to do is set a pointer. Since you didn't specify any real requirements, one solution could be as follows:
Changing the signature a bit so now you have a pointer to an already allocated node:
void insertNode(node *&root, node *newNode) {
if (root == NULL) {
root = newNode;
return;
}
if (root->left == NULL) {
root-left = newNode;
return;
}
helperInsert(root->left, newNode);
return;
}
This will set the head (assuming I got the signature right), and otherwise check the left child.
void helperInsert(node *it, node *newNode) {
if (it->left == NULL) {
it->left = newNode;
return;
}
helperInsert(it->left, newNode);
return;
}
This is obviously a flawed approach (the tree will not be balanced at the slightest), almost treating the tree as a linked list, but to my best understanding of the question, this is an example of how it can be done.
In
else if (root->left == NULL)
root->left=insert(root->left,key);
you know root->left is NULL so why to do the recursive call ?
Of course same for the next else
The following code only works for the very first three nodes.
If both left and right are non NULL you do not insert, that time it was necessary to do the recursive call on one of the two branches, and you will consider the key (so insert ordered) to decide which one. Note that the 2 tests to NULL you did are not correct if you insert to have a sorted tree ...
The heap advice is most sound. You don't need to heapify anything, just follow the rules that an element at index k has children at 2*k + 1 and 2*k + 2.
Another approach, useful when there is no array, but the nodes are generated on the fly, is to fill the tree level-wise. Notice that at level k there are 2 ** k slots, conveniently indexed by a k-bit integer. Interpret the index as a path down the tree (clear bit tells to follow left child, set bit tells to follow a right one), along the lines of:
void insert_node(struct node * root, struct node * node, unsigned mask, unsigned path)
{
while ((mask >> 1) != 1) {
root = mask & path? root->right: root->left;
}
if (mask & path) {
assert (root->right == NULL);
root->right = node;
} else {
assert (root->left == NULL);
root->left = node;
}
}
void fill_level_k(struct node * root, unsigned k)
{
unsigned slots = 1 << k;
for (unsigned slot = 0; slot < slots; slot++) {
struct node * node = generate_new_node();
insert_node(root, node, slots, slot);
}
}
I have pre-written code that I'm trying to wrap my head around:
int maxExtract(node **tree)
{
node *prev = NULL;
node *curr = *tree;
int ret;
if(curr == NULL)
{
printf("Tree is empty!\n");
exit(-1);
}
while( curr->right != NULL )
{
prev = curr;
curr = curr->right;
}
ret = curr->data;
if( prev != NULL )
prev->right = curr->left;
else if( curr == *tree )
*tree = curr->left;
free(curr);
return ret;
}
I understand everything except the else if (curr == *tree) condition. I think it's saying that if the max node ends up being the root. However, wouldn't you need to change more connections than that after the else if, like to connect the right and left side of the tree to this new root after extracting the old one?
I think it's saying that if the max node ends up being the root.
That is exactly what it means and, if that's the case, then there can be nothing in the right side of that node because, if there were, the maximum would be somewhere in that (right) sub-tree, not at the root.
So let's consider the tree where the root is the maximum (and A1/A2 are arbitrary sub-trees, including empty ones):
MAX
/
x
/ \
A1 A2
To extract the maximum value, what you want to be left with is simply:
x
/ \
A1 A2
So the operation you want to perform is to make x the new root of the tree - this is done with the line in your code:
*tree = curr->left;
I'd probably write it slightly differently to explicitly handle the disparate cases rather than relying on things happening or not happening depending on various decisions in the middle of the code. By that, I mean:
int maxExtract (node **tree) {
// Handle empty tree as error.
if (*tree == NULL) {
printf ("Tree is empty!\n");
exit (-1);
}
// Handle root is max, i.e., has no right subtree.
if ((*tree)->right == NULL) {
node *nodeToDelete = *tree; // Save root for deletion.
int retVal = nodeToDelete->data; // Get data to return.
*tree = nodeToDelete->left; // Set new root.
free (nodeToDelete); // Delete old root.
return retVal; // Return old root value.
}
// Locate max and its previous.
node *prev = *tree;
node *curr = (*tree)->right;
while (curr->right != NULL) {
prev = curr;
curr = curr->right;
}
// Max has no right sub-tree but it MAY have a left one
// which needs to be transferred as-is to the right of prev.
int retVal = curr->data; // Get data to return.
node *nodeToDelete = curr; // Save root for deletion.
prev->right = curr->left; // Transfer left sub-tree (or null).
free (nodeToDelete); // Delete old max.
return retVal; // Return old max value.
I think there are multiple errors in my code for deleting a node from a BST. I just can't figure out what! Here's my code. Thanks in advance!
void del(int val){
help = root;
f = help;
while (help){
if(help->data==val) break;
f = help;
if (val > help-> data) help = help->right;
else help = help->left;
} if(help->data != val) printf("\nElement not found!");
else{
printf("Element found!");
target = help;
if(val>f->data){
if(target->right && !target->left) {f->right = target->right; f = target->right;}
else {f->right = target->left; f = target->left;}
} else{
if(target->right && !target->left) {f->left = target->right; f = target->right;}
else {f->left = target->left; f = target->left;}
}
while(help ->right) help = help->right;
if(help->left) help = help->left;
f->right = help;
free(target);
}
}
One error that I spot is that if one were to delete the left node in the tree, then the last few lines might not work since they are not symmetric. So, let us say, the tree has root as 6 and left-child as 4 and right-child as 8. Now, you want to delete 4. So, after you have found the node in the first while clause, you would hit the else clause of "if (val > f->data){". At this point, f would point to 6, target and help would point to 4. Now, you are setting the left of f to right of target, so left of 6 would point to NULL and f itself would point to NULL. So, far so good! But, once you get into the while loop, since help has no right node, help would continue to point to 6. In the end, you make the right node of f (btw, f is already NULL at this point) to help and you would actually end up crashing!
while (help->right)
help = help->right;
if (help->left)
help = help->left;
f->right = help;
Another error is that you do not update the root pointer, incase you end up deleting the root node.
One simpler approach would be to divide this into three cases. I am providing code for all the three cases. Use a sample tree for each of these three cases and then debug/test it.
First, if the found node (which your file while loop is doing) has no child nodes, then delete it and set its parent to NULL and you are done. Here is a rough-first cut of the first case:
/* If the node has no children */
if (!help->left && !help->right) {
printf("Deleting a leaf node \n");
f = help->parent;
if (f) {
if (value > f->value)
f->right = NULL;
else
f->left = NULL;
}
/* If deleting the root itself */
if (f->value == root) {
root = NULL;
}
free(help);
return 0;
}
Second, if the found node has only child (left or right), then splice it out and the child of the found node becomes hte child of the parent node. Here is the second case:
/* If the node has only one child node */
if ((help->left && !help->right)
|| (!help->left && help->right)) {
printf("Deleting a node with only one child \n");
f = help->parent;
if (help->left) {
child_node = help->left;
} else {
child_node = help->right;
}
if (f) {
if (value > f->value) {
f->right = child_node;
} else {
f->left = child_node;
}
} else {
/* This must be the root */
root = child_node;
}
free(help);
return 0;
}
The third case is tricky -- here the found node has two child nodes. In this case, you need to find the successor of the node and then replace the value of the found node with the successor node and then delete the successor node. Here is the third case:
/* If the node has both children */
if (help->left && help->right) {
successor_found = find_successor(help, help->data);
printf("Deleting a node with both children \n");
if (successor_found) {
successor_value = successor_found->value;
del(successor_found->value);
help->value = successor_value;
}
return 0;
}
And, here is the code to find successor:
binary_node_t *node find_successor(binary_node_t *node, int value) {
binary_node_t *node_found;
if (!node) {return NULL; }
node_found = node;
old_data = node->data;
/* If the node has a right sub-tree, get the min from the right sub-tree */
if (node->right != NULL) {
node = node->right;
while (node) {
node_found = node;
node = node->left;
}
return node_found;
}
/* If no right sub-tree, get the min from one of its ancestors */
while (node && node->data <= old_data) {
node = node->parent;
}
return (node);
}
typedef struct xxx {
struct xxx *left;
struct xxx *right;
int data;
} ;
#define NULL (void*)0
#define FREE(p) (void)(p)
void treeDeleteNode1 (struct xxx **tree, int data)
{
struct xxx *del,*sub;
/* Find the place where node should be */
for ( ; del = *tree; tree = (data < del->data) ? &del->left : &del->right ) {
if (del->data == data) break;
}
/* not found: nothing to do */
if ( !*tree) return;
/* When we get here, `*tree` points to the pointer that points to the node_to_be_deleted
** If any of its subtrees is NULL, the other will become the new root
** ,replacing the deleted node..
*/
if ( !del->left) { *tree = del->right; FREE(del); return; }
if ( !del->right) { *tree = del->left; FREE(del); return; }
/* Both subtrees non-empty:
** Pick one (the left) subchain , save it, and set it to NULL */
sub = del->left;
del->left = NULL;
/* Find leftmost subtree of right subtree of 'tree' */
for (tree = &del->right; *tree; tree = &(*tree)->left) {;}
/* and put the remainder there */
*tree = sub;
FREE(del);
}
To be called like:
...
struct xxx *root;
...
treeDeleteNode1( &root, 42);
...