# Deletion in Threaded Binary Search Tree Deletion in Threaded Binary Search Tree

## Introduction

A. J. Perlis and C. Thornton proposed a new version of a binary tree called “Threaded Binary Tree” that uses NULL pointers to improve its traversal process. In a threaded binary tree, NULL pointers are replaced by references of other nodes in the tree. These extra references are called threads

Although threads can be deleted in any binary tree, it is most efficient to delete threads in a binary search tree or its variants, i.e. a tree that meets the Binary Search Tree properties. As a result, the Threaded Binary Tree we will use in this blog is a Binary Search Tree having Threads (threaded binary search tree).

Node Structure of Threaded Binary tree

```struct Node{
int data;
Node *left, *right;

// false if the right pointer points to inorder successor

// false if the left pointer points to inorder predecessor
};
```

Before moving directly to Deletion in the Threaded Binary Search Tree, let us first look at the basics of the Threaded Binary Tree

## Deletion in Threaded Binary Search Tree

For deletion in the Threaded Binary Search Tree, we will first search the value to be deleted, and then we will see the possible cases for deleting the node in which the value is present.

```// For deleting the value from threaded BST with the given root
// and returning a new root of BST

struct Node* dThreadedBST(struct Node* root, int value)
{
// Function for initializing the parent node to NULL and current node to root.
struct Node *parent  = NULL, *current = root;

// Set true if value is found
int found = 0;

// Now, we will search value in BST
while (current != NULL) {
if (value == current->data) {
found = 1;
break;
}
parent  = current;
if (value < current->data) {
if (current->leftThread == false)
current = current->left;
else
break;
}
else {
if (current->rightThread == false)
current = current->right;
else
break;
}
}

if (found == 0)
printf("The value is not present in tree\n");

// When the node to be deleted has two children
else if (current->leftThread == false && current->rightThread == false)
root = case3(root, parent , current);

// When the node to be deleted has only left child
else if (current->leftThread == false)
root = case2(root, parent , current);

// When the node to be deleted has only right child
else if (current->rightThread == false)
root = case2(root, parent , current);

// When a leaf node needs to be deleted
else
root = case1(root, parent , current);

return root;
}
```

We can use the delete operation to remove a node from a threaded binary search tree. However, there are three cases for removing it.

Case 1: When a leaf node needs to be deleted

When deleting a leaf Node in BST, the left or right pointer of the parent node is set to NULL. Whereas in Threaded binary search trees, it is turned into a thread instead of setting the pointer to NULL.

If the leaf Node is the left child of its parent, then after deletion, the parent’s left pointer should become a thread referring to its predecessor.

Let’s understand this using an example.

In the tree given above, if we delete node 18, then the left pointer of its parent node, node 20, will point to its predecessor node 15 (as shown below).

Similarly, If the leaf Node is the right child of its parent, then after deletion, the parent’s right pointer should become a thread referring to its successor. After deletion, the Node that was the in-order successor of the leaf Node will now become the in-order successor of the parent Node.

Now, let’s have a look at the code:

```// Here, 'parent ' is a pointer referring to the parent node
// and 'current' is a pointer to the current node.

struct Node* case1 (struct Node* root, struct Node* parent, struct Node* current)
{
// If root node has to be deleted
if (parent  == NULL)
root = NULL;

// If the node to be deleted is left child of its parent
else if (current == parent ->left) {
parent ->leftThread = true;
parent ->left = current->left;
}

// If the node to be deleted is the right child of its parent
else {
parent ->rightThread = true;
parent ->right = current->right;
}

// Now memory is freed, and new root is returned
free(current);
return root;
}
```

Case 2: When the node to be deleted has only one child

After deleting the Node like in a BST the inorder successor and predecessor of the Node are found.

```s = inSucc(current);
p = inPred(current);
```

If Node to be deleted has a left subtree, then after deletion, the right thread of its predecessor should point to its successor.

Let’s understand this using an example.

In the figure given above, node 24 has node 23 as its predecessor and node 30 as its successor. So, after deleting node 24, node 30 becomes the successor of node 23, so the right thread of 23 will point to 30 (as shown in the figure given below).

Similarly, if Node to be deleted has a right subtree, then after deletion, the left thread of its successor should point to its predecessor.

Now, let’s have a look at the code:

```// Here, 'parent ' is a pointer referring to the parent node
// and 'current' is a pointer to the current node.

struct Node* case2 (struct Node* root, struct Node* parent, struct Node* current)
{
struct Node* child;

// First initialize whether the child Node to be deleted has left child.
if (current->leftThread == false)
child = current->left;

// or a right child
else
child = current->right;

// If root node has to be deleted
if (parent  == NULL)
root = child;

// If the node to be deleted is left child of its parent
else if (current == parent ->left)
parent ->left = child;

// If the node to be deleted is right child of its parent
else
parent ->right = child;

// Find successor and predecessor
Node* s = inSucc(current);
Node* p = inPred(current);

// If current node has left subtree
if (current->leftThread == false)
p->right = s;

// If current node has right subtree.
else {
if (current->rightThread == false)
s->left = p;
}

// Now memory is freed and new root is returned
free(current);
return root;
}
```

Case 3: When the node to be deleted has two children

We find the in-order successor of the current Node (Node to be deleted) and then copy the information of this successor into the current Node. After this, the in-order successor Node is deleted using either Case 1 or Case 2.

Let’s have a look at the code:

```// Here, 'parent ' is a pointer referring to the parent node
// and 'current' is a pointer to the current node
struct Node* case3(struct Node* root, struct Node* parent,  struct Node* current)
{
// Find the inorder successor
struct Node* parsucc = current;
struct Node* succ = current->right;

// Find the leftmost child
parsucc = succ;
succ = succ->left;
}

current->data = succ->data;

if (succ->leftThread == true && succ->rightThread == true)
root = case1(root, parsucc, succ);
else
root = case2(root, parsucc, succ);

return root;
}
```

## Complete Code for Deletion

```#include <bits/stdc++.h>
using namespace std;

struct Node {
struct Node *left, *right;
int data;

// false if the left pointer points to a predecessor of in Inorder Traversal

// false if the right pointer points to a predecessor of in Inorder Traversal
};

// For inserting a Node in Threaded Binary Tree
struct Node* insert(struct Node* root, int key)
{
// Searching for a Node with given value
Node* current = root;
Node* parent = NULL;

while (current != NULL) {

// If value already exists, then we will return the root
if (key == (current->data)) {
printf("Duplicate value !\n");
return root;
}

// Updating the parent pointer
parent = current;

// Taking the left subtree
if (key < current->data) {
if (current->leftThread == false)
current = current->left;
else
break;
}

// Taking the right subtree
else {
if (current->rightThread == false)
current = current->right;
else
break;
}
}

// Creating a new Node
Node* temp = new Node;
temp->data = key;

if (parent == NULL) {
root = temp;
temp->left = NULL;
temp->right = NULL;
}

else if (key < (parent->data)) {
temp->left = parent->left;
temp->right = parent;
parent->left = temp;
}

else {
temp->left = parent;
temp->right = parent->right;
parent->right = temp;
}

return root;
}

// For returning the inorder successor using left and right children
struct Node* inSucc(struct Node* current)
{
if (current->rightThread == true)
return current->right;

current = current->right;
while (current->leftThread == false)
current = current->left;

return current;
}

// For returning inorder successor using rightThread
struct Node* inorderSuccessor(struct Node* current)
{
// If rightThread is set, we can quickly find
if (current->rightThread == true)
return current->right;

// Or return the leftmost child of right subtree
current = current->right;
while (current->leftThread == false)
current = current->left;
return current;
}

// Print the threaded tree
void inorder(struct Node* root)
{
if (root == NULL)
printf("Tree is empty");

// Taking leftmost Node
struct Node* current = root;
while (current->leftThread == false)
current = current->left;

while (current != NULL) {
printf("%d ", current->data);
current = inorderSuccessor(current);
}
}

struct Node* inPred(struct Node* current)
{
if (current->leftThread == true)
return current->left;

current = current->left;
while (current->rightThread == false)
current = current->right;
return current;
}

// Here 'parent ' is a pointer referring to the parent node
// and 'current' is a pointer to the current node.

struct Node* case1(struct Node* root, struct Node* parent,struct Node* current)

{
// If root node has to be deleted
if (parent == NULL)
root = NULL;

// If the node to be deleted is left child of its parent
else if (current == parent->left) {
parent->left = current->left;
}

// If the node to be deleted is the right child of its parent
else {
parent->right = current->right;
}

// Now memory is freed and new root is returned
free(current);
return root;
}

// Here 'parent ' is a pointer referring to the parent node
// and 'current' is a pointer to the current node.

struct Node* case2 (struct Node* root, struct Node* parent, struct Node* current)
{
struct Node* child;

// First initialize whether the child Node to be deleted has left child.
if (current->leftThread == false)
child = current->left;

// or a right child
else
child = current->right;

// If root node has to be deleted
if (parent  == NULL)
root = child;

// If the node to be deleted is left child of its parent
else if (current == parent ->left)
parent ->left = child;

// If the node to be deleted is right child of its parent
else
parent ->right = child;

// Find successor and predecessor
Node* s = inSucc(current);
Node* p = inPred(current);

// If current node has left subtree
if (current->leftThread == false)
p->right = s;

// If current node has right subtree.
else {
if (current->rightThread == false)
s->left = p;
}

// Now memory is freed and new root is returned
free(current);
return root;
}

// Here 'parent' is a pointer referring to the parent node
// and 'current' is a pointer to the current node
struct Node* case3(struct Node* root, struct Node* parent,  struct Node* current)
{
// Find the inorder successor
struct Node* parsucc = current;
struct Node* succ = current->right;

// Find the leftmost child
parsucc = succ;
succ = succ->left;
}

current->data = succ->data;

if (succ->leftThread == true && succ->rightThread == true)
root = case1(root, parsucc, succ);
else
root = case2(root, parsucc, succ);

return root;
}

// For deleting the value from threaded BST with the given root
// and returning a new root of BST

struct Node* dThreadedBST(struct Node* root, int value)
{
// For initializing the parent node as NULL and current node as root.
struct Node *parent  = NULL, *current = root;

// Set true if value is found
int found = 0;

// Searching value in BST
while (current != NULL) {
if (value == current->data) {
found = 1;
break;
}
parent  = current;
if (value < current->data) {
if (current->leftThread == false)
current = current->left;
else
break;
}
else {
if (current->rightThread == false)
current = current->right;
else
break;
}
}

if (found == 0)
printf("The value not present in tree\n");

// When the node to be deleted has two children
else if (current->leftThread == false && current->rightThread == false)
root = case3(root, parent , current);

// When the node to be deleted has only left child
else if (current->leftThread == false)
root = case2(root, parent , current);

// When the node to be deleted has only right child
else if (current->rightThread == false)
root = case2(root, parent , current);

// When a leaf node needs to be deleted
else
root = case1(root, parent , current);

return root;
}

// Driver Program
int main()
{
struct Node* root = NULL;

root = insert(root, 45);
root = insert(root, 8);
root = insert(root, 24);
root = insert(root, 20);
root = insert(root, 15);
root = insert(root, 30);
root = insert(root, 23);
root = insert(root, 18);

root = dThreadedBST(root, 24);
inorder(root);

return 0;
}
```

Output

`8 15 18 20 23 30 45`

Time complexity – O(h), where h is the height of the threaded binary search tree. The height of the tree can be ‘n’ in the worst case, and all the keys are deleted in ascending or descending order (Skewed Tree) where all the nodes except the leaf have only one child, and we may have to travel from root to the deepest leaf node.

Space complexity – O(1), as we are not using any additional auxiliary space.

## Frequently Asked Questions

What is a Threaded Binary SearchTree?

A threaded binary search tree is a variation of a normal binary search tree. In a threaded binary search tree, if the left pointer of a node is NULL, it is pointed to its in-order predecessor (if it exists), and if the right pointer of a node is NULL, it is pointed to its in-order successor (if it exists) using links called as threads.

How do you perform deletion in a Threaded Binary search tree?

Yes, we can perform deletion in a threaded binary search tree like it is performed in a binary search tree. First, we will search the value to be deleted and then see the possible cases for deleting it. There are mainly three cases when performing deletion:
1. When a leaf node is to be deleted.
2. When the node to be deleted has only one child.
3. When the node to be deleted has two children.

What are the advantages of a Threaded Binary Tree?

Some advantages of a Threaded Binary tree are:
1. They do not require a stack or recursion for their traversal.
2. In threaded binary trees, memory is not wasted as whenever a node’s left/right pointer is NULL, its inorder predecessor/successor is stored.
3. We can do a backward traversal in a double-threaded binary tree.
4. In-order traversal is fast in a threaded binary tree than a normal binary tree.

## Key Takeaways

In this article, we learned about ways to delete a node in threaded binary search trees. Majorly three prominent cases arrive when we try to delete a node. The first one is when the node is a leaf node, the second one when the node to be deleted has only one child (that means left or right pointer is not NULL), and the third one is when the node has two children (that means both left and right child pointers are not NULL). Hence, we traversed the tree, keeping in mind all three cases.

By: Mehak Goel