How recursion works for this binary search tree algorithm - c

I have the following binary search tree, with root node 20. The question I'm trying to answer is, if we apply the function t = deleteRoot(t), what will be the value of the new root node, as well as its immediate left and right children (e.g. the current root node is 20 with immediate left child 11 and immediate right child 32). I scribbled at least 10 pages over the last 2 hours trying to solve this, but the recursion is killing me. Can someone please help me visualize this - i.e some way of thinking which allows me to deal with recursion. I'm not very good at visualizing how recursion works but I can somewhat implement it. Thanks very much. By the way, the answer is root node: 21 with left child 11 and right child 32.
My attempt:
The question tells us to start with t=deleteRoot(t).
parent = node containing 25
succ = node containing 21
succval = 21
then we get to
t = TreeDelete(t, succval)
then I get a bit lost as to how the TreeDelete function works
t->left = TreeDelete(t->left, key) ...etc
deleteRoot(Tree t) function
// delete root of tree
Tree deleteRoot(Tree t)
{
Link newRoot;
// if no subtrees, tree empty after delete
if (t->left == NULL && t->right == NULL) {
free(t);
return NULL;
}
// if only right subtree, make it the new root
else if (t->left == NULL && t->right != NULL) {
newRoot = t->right;
free(t);
return newRoot;
}
// if only left subtree, make it the new root
else if (t->left != NULL && t->right == NULL) {
newRoot = t->left;
free(t);
return newRoot;
}
// else (t->left != NULL && t->right != NULL)
// so has two subtrees
// - find inorder successor (grab value)
// - delete inorder successor node
// - move its value to root
Link parent = t;
Link succ = t->right; // not null!
while (succ->left != NULL) {
parent = succ;
succ = succ->left;
}
int succVal = succ->value;
t = TreeDelete(t,succVal);
t->value = succVal;
return t;
}
Tree TreeDelete(Tree t, Key k) function:
Tree TreeDelete(Tree t, Key k)
{
Tree deleteRoot(Tree);
if (t == NULL)
return NULL;
int diff = cmp(k,key(t->value));
if (diff == 0)
t = deleteRoot(t);
else if (diff < 0)
t->left = TreeDelete(t->left, k);
else if (diff > 0)
t->right = TreeDelete(t->right, k);
return t;
}

By the way, the answer is root node: 21 with left child 11 and right child 32.
Well, it is one solution but not the only solution.
18 with left child 11 and right child 32 will also be a solution.
When deleting the root, the new root can be selected as
The highest number in the left subtree
or
The lowest number in the right subtree
So copy the value of the selected node to the current root. And then delete the selected node. If the selected node has children, you can repeat the process recursively.

In the case of deletion, if the node to be deleted has two children:
Find the successor or the predecessor
Replace the node with the contents of the successor/predecessor
Call delete on the successor/predecessor (this way the size will be decremented)
Return the node
The successor is the highest element on the right subtree while the predecessor is the lowest element on the left subtree. In your case, the successor would be 21 and the predecessor would be 18.

Related

Deletion in BST

I was trying to perform deletion in a binary search tree (BST), but it was giving a segmentation fault after printing the deleted array.
treeNode *minVal(treeNode *root)
{
if(root == NULL || root->left==NULL)
return root;
else
minVal(root->left);
}
treeNode *deleteBST(treeNode *root,int value)
{
treeNode *tempNode;
if(value>root->value)
deleteBST(root->right,value);
else if(value<root->value)
deleteBST(root->left,value);
else
{
if(root->left==NULL)
{
tempNode = root->right;
free(root);
return tempNode;
}
else if(root->right==NULL)
{
tempNode = root->left;
free(root);
return tempNode;
}
else
{
tempNode = minVal(root->right);
root->value=tempNode->value;
root->right = deleteBST(root->right,tempNode->value);
}
}
return root;
}
Presumably the point of deleteBST() returning a treeNode * is that the return value points to the new root of the (sub)tree. The new root will differ from the original one if the deleted value was found in the original root, so some means of updating the root is required.
That needs to be handled appropriately by this function's callers, including this function itself when it performs recursive calls. Your function fails to do this.
Your function also fails to properly handle the case when the specified value is not found in the tree. It will eventually attempt to dereference a null pointer if such a value is passed.
And the actual deletion performed by your function is totally inadequate. It frees the node where the value is found, but it does not adjust the subtree rooted at that node to have a valid structure, and it leaves the parent of the deleted node with a (then) invalid child pointer.
The general scheme for deletion from a BST would be like this:
if the root, R, of the tree is null then return null; otherwise,
if the value to delete is less than the value of R, then
delete it from the left subtree and update R's left pointer to point to the new root of the left subtree; otherwise,
if the value to delete is greater than the value of R, then
delete it from the right subtree and update R's right pointer to point to the new root of the right subtree; otherwise,
the value to delete is the value of R itself. In this case,
Select a new root for this subtree:
if both R's children are null then the new root is also null.
if exactly one child is null then the other is the new root.
if neither child is null then you can choose either the smallest node in the right subtree or the largest one in the left subtree. These are R's immediate in-order successor and predecessor, respectively.
In the case where neither of R's children is null, update the subtree appropriately. Supposing that the smallest node of the right subtree, MR, is the selected new root, you must
remove MR from its current parent by updating the parent's pointer to it to point instead at MR's right child (which might or might not be null). Including when the parent is R.
update MR's left and right child pointers to be the same as R's.
Free R.
return the root of the subtree (original or new, as appropriate)
updated working code is attached with comments to the errors.
treeNode *minVal(treeNode *root)
{
if(root == NULL || root->left==NULL)
return root;
else
return minVal(root->left);//1.returning a value is a must here
}
treeNode *deleteBST(treeNode *root,int value)
{
treeNode *tempNode;
if(root==NULL)//2.handling the base case
return NULL;
if(value>root->value)
return deleteBST(root->right,value);
else if(value<root->value)
return deleteBST(root->left,value);
else
{
if(root->left==NULL)
{
tempNode = root->right;
free(root);
return tempNode;
}
else if(root->right==NULL)
{
tempNode = root->left;
free(root);
return tempNode;
}
else
{
tempNode = minVal(root->right);
root->value=tempNode->value;
root->right = deleteBST(root->right,tempNode->value);
return root;//can be skipped
}
}
return root;
}

Deleting a node in a bst in c

void MorrisTraversal(tNode* root)
{
tNode *current, *pre;
if (root == NULL)
return;
current = root;
while (current != NULL)
if (current->left == NULL) {
current = current->right;
}
else {
pre = current->left;
while (pre->right != NULL
&& pre->right != current)
pre = pre->right;
if (pre->right == NULL) {
pre->right = current;
current = current->left;
}
else {
pre->right = NULL;
current = current->right;
}
}
}
}
I use this function to travers the bst, i also have a function (delete) that takes a node as parameter and delets it from the tree.
I'd like for example to remove from the tree all nodes whose value is 4, is it possible to do so using the functions mentioned above?
Like traversing the tree one time and removing all the nodes with a certain property.
I hope my problem it's clear...
Thanks in advance!
It is possible, but you will need to modify your Traversal function.
Currently MorrisTraversal traverses the tree, but it doesn't do anything to any node. You could modify MorrisTraversal to call a function on the current node (probably on the line after while (current != NULL).
I would first try putting a simple print function/line there that prints the value of the current node and run it to verify your tree traversal works as expected.
Then you could change the print function to modify the node in some way.
If you do delete the node, you will have to be careful to clean up the tree. Eg. if you have the following tree Where A is the root node:
A-B-C
|
D-E
|
F
What happens if you delete B? Will you move C, A. or D into B's place?
Good luck!

is this Ternary expression redundant in splay function

https://www.geeksforgeeks.org/splay-tree-set-1-insert/
When I was learning about splay trees, I referred to this article and had a little doubt about the code in it.
this is splay function in this article
struct node *splay(struct node *root, int key)
{
// Base cases: root is NULL or key is present at root
if (root == NULL || root->key == key)
return root;
// Key lies in left subtree
if (root->key > key)
{
// Key is not in tree, we are done
if (root->left == NULL) return root;
// Zig-Zig (Left Left)
if (root->left->key > key)
{
// First recursively bring the key as root of left-left
root->left->left = splay(root->left->left, key);
// Do first rotation for root, second rotation is done after else
root = rightRotate(root);
}
else if (root->left->key < key) // Zig-Zag (Left Right)
{
// First recursively bring the key as root of left-right
root->left->right = splay(root->left->right, key);
// Do first rotation for root->left
if (root->left->right != NULL)
root->left = leftRotate(root->left);
}
// Do second rotation for root
return (root->left == NULL)? root: rightRotate(root);
}
else // Key lies in right subtree
{
// Key is not in tree, we are done
if (root->right == NULL) return root;
// Zag-Zig (Right Left)
if (root->right->key > key)
{
// Bring the key as root of right-left
root->right->left = splay(root->right->left, key);
// Do first rotation for root->right
if (root->right->left != NULL)
root->right = rightRotate(root->right);
}
else if (root->right->key < key)// Zag-Zag (Right Right)
{
// Bring the key as root of right-right and do first rotation
root->right->right = splay(root->right->right, key);
root = leftRotate(root);
}
// Do second rotation for root
return (root->right == NULL)? root: leftRotate(root);
}
}
Here is a snippet from the source code return (root->left == NULL)? root: rightRotate(root);, it appears in the last paragraph of the function.
My question is if I can write like thisreturn rightRotate(root), Because we have already judged whether this pointer is NULL above, It seems to me that after we do the rotate operation, the root->left can not be NULL. If this pointer can be null, hope to point out the situation that does not hold
is this Ternary expression redundant in splay function
No, root = rightRotate(root); and root = leftRotate(root); change root.

Binary Tree Extraction code

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.

AVL Tree Iterator in C

I'm trying to create an AVL Tree iterator, but I'm having trouble doing so. This is the code I have to get the first node, which successfully returns the minimum.
AVLPtr node = iter->list->root;
AVLPtr current = iter->current;
AVLPtr last = iter->last;
AVLPtr parent;
if(current == NULL || current->parent == NULL)
parent = NULL;
else
parent = iter->current->parent;
if(last == NULL && current == NULL){
while(node->leftChild != NULL){
node = node->leftChild;
iter->current = node;
}
}
I'm getting a SegFault when I go to get the next node. I think this is because I am actually changing the parent of the node to NULL in my first if statement. I then mess up my list by eventually making the root the minimum in the while loop. My question is how do I get this first node without changing the parent or root nodes? Or is there something else that I am missing?
EDIT: Should I extract the object that each node in the tree holds into a separate linked list by using a recursive inorder call?
I do not know what do you mean by first element, but I will assume that you mean the leftmost leaf. If so, then you can find it this way:
AVLPtr first = iter->list->root;
AVLPtr last = iter->list->root;
while(first->leftChild != NULL){
first = first->leftChild;
}
iter->current = first;
You should always change iter->current and use its links to left, right and parent.

Resources