0% found this document useful (0 votes)
4 views

Binary Search Tree

Binary Search Trees (BST) are data structures that maintain unique keys with left child nodes containing lesser values and right child nodes containing greater values. The document explains the structure, insertion, and traversal methods (preorder, inorder, postorder) of BSTs, as well as deletion rules for different node scenarios. It includes C code examples for implementing these operations and highlights the efficiency of searching and manipulating data within a BST compared to arrays and linked lists.

Uploaded by

akkutuppu
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Binary Search Tree

Binary Search Trees (BST) are data structures that maintain unique keys with left child nodes containing lesser values and right child nodes containing greater values. The document explains the structure, insertion, and traversal methods (preorder, inorder, postorder) of BSTs, as well as deletion rules for different node scenarios. It includes C code examples for implementing these operations and highlights the efficiency of searching and manipulating data within a BST compared to arrays and linked lists.

Uploaded by

akkutuppu
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 67

Binary Search Tree

Binary Search Tree


Binary search trees are a special kind of tree which follows the below rules,
1. Every Node should have a unique key.
2. The key in the left node should be less than the parent key.
3. The key in the right node should be greater than the parent key
4. Duplicate keys are not allowed.

Sample binary search tree with 7 nodes.


1. Root Node
The topmost node. 100 is a root node.
2. Internal Nodes
The nodes intermediate between root and the leaf node. 50, 200 are
intermediate nodes.
3. Leaf Nodes
The bottom-most nodes or the node with no reference link. 10, 60, 150, 300 are
leaf nodes.

Why binary search tree?


If we arrange the data based on the above rules, we can effectively manipulate
them.
Example1:
If we need to search element 10, we can do it effectively like below,
Check if the root node has the value 10. root node value = 100. 10 < 100.
Hence 10 should be present in the left subtree (right subtree must have values >
100). So we can skip entire right subtree from the searching.
1. root's key value = 100. 10 < 100.
2. So we can skip the right subtree from the searching.
Example2:
Check if the left subtree's root has the value 10. Next left root value = 50. again
10 < 50.
So we can skip the right subtree from the searching as the key value less than
the root.
1. Left subtree's root key value = 50. 10 < 50.
2. So we can skip the right subtree from the searching.

Finally, we can find the node with value 10 in minimal search count. That's
how the binary search tree effectively improves the data manipulation.

In normal array and linked list, there is no way we can skip some element from
the searching as they don't follow any data arrangement rules like the binary
search tree.

Binary Search Tree - Node Structure


struct node
{
int key;
struct node *left;
struct node *right;
};
key - It can be any data type. char, float, double, string.
*left - Reference to the left node. It holds the memory address of the left child.
*right - Reference to the right node. It holds the memory address of the right
child.

Let's create a sample BST node:


struct node
{
int key;
struct node *left;
struct node *right;
};

//declaring a node
struct node *root;

//allocating memory for the node


root = malloc(sizeof(struct node));
Assign values to the node:
struct node
{
int key;
struct node *left;
struct node *right;
};
//declaring a node
struct node *root;
//allocating memory for the node
root = malloc(sizeof(struct node));
//assigning values
root->key = 10;
root->left = NULL;
root->right = NULL;
Visual Representation:

1. root node's memory address 1024. root=>data = 10. root=>left = NULL.


root=>right = NULL.
Inserting a node in a binary search tree:
Given a binary search node and a value, insert the new node into the BST in the
correct place.

Example:
Algorithm:
1. Create a new BST node and assign values to it.
2. insert(node, key)
i) If root == NULL,
return the new node to the calling function.
ii) if root=>data < key
call the insert function with root=>right and assign the return value
in root=>right.
root->right = insert(root=>right,key)
iii) if root=>data > key
call the insert function with root->left and assign the return value in
root=>left.
root=>left = insert(root=>left,key)
3. Finally, return the original root pointer to the calling function.
Binary search tree insertion code:
struct node *insert(struct node *root, int val)
{
/*
* It will handle two cases,
* 1. if the tree is empty, return new node in the root
* 2. if the tree traversal reaches NULL, it will return the new node
*/
if(root == NULL)
return getNewNode(val);
/*
* if given val is greater than root->key,
* we should find the correct place in the right subtree and insert the new node
*/
if(root->key < val)
root->right = insert(root->right,val);
/*
* if given val is smallar than root->key,
* we should find the correct place in the left subtree and insert the new node
*/
else if(root->key > val)
root->left = insert(root->left,val);
/*
* It will handle two cases
* (Prevent the duplicate nodes in the tree)
* 1.if root->key == val it will straight away return the address of the root node
* 2.After the insertion, it will return the original unchanged root's address
*/
return root;
}
The getNewNode function:
This function allocates and returns the new node with the given data and the left
and right pointer as NULL.

struct node *getNewNode(int val)


{
struct node *newNode = malloc(sizeof(struct node));
newNode->key = val;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
Visual Representation of binary search tree insertion
algorithm:
Follow the step numbers(given in the circle) to understand the code flow
correctly.
Try to draw the diagram by yourself for better understanding.
1. insert 100
Diagram Explanation:
1. Main Function
root = NULL. address of root = 4444. And the main function calling the insert
function with root and an element 100. root = insert(root, 100);
2. Insert Function
The insert function receives root (NULL) and an element 100.
Since root == NULL, the first if statement will take control. i.e.
if(root == NULL)
return getNewNode(val);
It will call the getNewNode function with an element 100.
3. getNewNode() function creates a new node with the given value. Let's
assume that the new node's address as 1024. Then 1024 will be returned to the
insert function.
4. Insert function returns the received new node's address(1024) to the main
function. Now root will receive the new node's address 1024.
5. Finally, the new BST.
2. insert 50
1. insert 150
Implementation of Binary Search Tree Insertion:
/*
* Program : Binary Search Tree insertion
* Language : C
*/
#include<stdio.h>
#include<stdlib.h>
struct node
{
int key;
struct node *left;
struct node *right;
};
//this function will return the new node with the given value
struct node *getNewNode(int val)
{
struct node *newNode = malloc(sizeof(struct node));
newNode->key = val;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}

struct node *insert(struct node *root, int val)


{
/*
* It will handle two cases,
* 1. if the tree is empty, return new node in root
* 2. if the tree traversal reaches NULL, it will return the new node
*/
if(root == NULL)
return getNewNode(val);
/*
* if given val is greater than root->key,
* we should find the correct place in right subtree and insert the new node
*/
if(root->key < val)
root->right = insert(root->right,val);
/*
* if given val is smallar than root->key,
* we should find the correct place in left subtree and insert the new node
*/
else if(root->key > val)
root->left = insert(root->left,val);
/*
* It will handle two cases
* (Prevent the duplicate nodes in the tree)
* 1.if root->key == val it will straight away return the address of the root node
* 2.After the insertion, it will return the original unchanged root's address
*/
return root;
}
/*
* it will print the tree in ascending order
* we will discuss about it in the upcoming tutorials
*/
void inorder(struct node *root)
{
if(root == NULL)
return;
inorder(root->left);
printf("%d ",root->key);
inorder(root->right);
}
int main()
{
struct node *root = NULL;
root = insert(root,100);
root = insert(root,50);
root = insert(root,150);
root = insert(root,50);

inorder(root);
return 0;
}

Output:
50 100 150
Preorder Traversal of Binary Search Tree:
Preorder traversal is one of the depth first tree traversal methods.
Preorder : Root - Left - Right

Algorithm:
 Visit or print the root.
 Traverse the left subtree.
 Traverse the right subtree.

Preorder traversal function:


//preorder traversal of binary search tree
void preorder(struct node *root)
{
if(root == NULL)
return;
//visit the root
printf("%d ",root->key);

//traverse the left subtree


preorder(root->left);

//traverse the right subtree


preorder(root->right);
}
Preorder Traversal Source Code:
/*
* Program : Preorder traversal of binary search tree
* Language : C
*/
#include<stdio.h>
#include<stdlib.h>

struct node
{
int key;
struct node *left;
struct node *right;
};
//return a new node with the given value
struct node *getNode(int val)
{
struct node *newNode;
newNode = malloc(sizeof(struct node));

newNode->key = val;
newNode->left = NULL;
newNode->right = NULL;

return newNode;
}

//inserts nodes in the binary search tree


struct node *insertNode(struct node *root, int val)
{
if(root == NULL)
return getNode(val);

if(root->key < val)


root->right = insertNode(root->right,val);

if(root->key > val)


root->left = insertNode(root->left,val);

return root;
}

//preorder traversal of the binary search tree


void preorder(struct node *root)
{
if(root == NULL)
return;
//visit the root
printf("%d ",root->key);

//traverse the left subtree


preorder(root->left);

//traverse the right subtree


preorder(root->right);
}

int main()
{
struct node *root = NULL;

root = insertNode(root,100);
root = insertNode(root, 50);
root = insertNode(root, 200);
root = insertNode(root, 10);
root = insertNode(root, 60);
root = insertNode(root, 150);
root = insertNode(root, 300);

preorder(root);

return 0;
}

Output:
100 50 10 60 200 150 300
Inorder Traversal of Binary Search Tree:
Inorder traversal is one of the depth first tree traversal methods.
Inorder traversal of binary search tree will produce the output in acending order.

Inorder : Left - Root - Right

Algorithm:
 Traverse the left subtree.
 Visit or print the root.
 Traverse the right subtree.
Inorder traversal function:
void inorder(struct node *root)
{
if(root == NULL)
return;

//traverse the left subtree


inorder(root->left);

//visit the root


printf("%d ",root->key);

//traverse the right subtree


inorder(root->right);
}
Inorder Traversal Source Code:
/*
* Program : Inorder traversal of binary search tree
* Language : C
*/
#include<stdio.h>
#include<stdlib.h>

struct node
{
int key;
struct node *left;
struct node *right;
};
//return a new node with the given value
struct node *getNode(int val)
{
struct node *newNode;
newNode = malloc(sizeof(struct node));

newNode->key = val;
newNode->left = NULL;
newNode->right = NULL;

return newNode;
}

//inserts nodes in the binary search tree


struct node *insertNode(struct node *root, int val)
{
if(root == NULL)
return getNode(val);

if(root->key < val)


root->right = insertNode(root->right,val);

if(root->key > val)


root->left = insertNode(root->left,val);

return root;
}

//inorder traversal of the binary search tree


void inorder(struct node *root)
{
if(root == NULL)
return;
//traverse the left subtree
inorder(root->left);

//visit the root


printf("%d ",root->key);

//traverse the right subtree


inorder(root->right);
}

int main()
{
struct node *root = NULL;

root = insertNode(root,100);
root = insertNode(root, 50);
root = insertNode(root, 200);
root = insertNode(root, 10);
root = insertNode(root, 60);
root = insertNode(root, 150);
root = insertNode(root, 300);

inorder(root);
return 0;
}

Output:
10 50 60 100 150 200 300
Postorder Traversal of Binary Search Tree:
Postorder traversal is one of the depth first tree traversal methods.
Postorder : Left - Right - Root

Algorithm:
 Traverse the left subtree.
 Traverse the right subtree.
 Visit or print the root.

Postorder traversal function:


//postorder traversal of binary search tree
void postorder(struct node *root)
{
if(root == NULL)
return;
//traverse the left subtree
postorder(root->left);

//traverse the right subtree


postorder(root->right);

//visit the root


printf("%d ",root->key);
}
Postorder Traversal Source Code:
/*
* Program : Postorder traversal of binary search tree
* Language : C
*/

#include<stdio.h>
#include<stdlib.h>

struct node
{
int key;
struct node *left;
struct node *right;
};
//return a new node with the given value
struct node *getNode(int val)
{
struct node *newNode;
newNode = malloc(sizeof(struct node));

newNode->key = val;
newNode->left = NULL;
newNode->right = NULL;

return newNode;
}

//inserts nodes in the binary search tree


struct node *insertNode(struct node *root, int val)
{
if(root == NULL)
return getNode(val);

if(root->key < val)


root->right = insertNode(root->right,val);

if(root->key > val)


root->left = insertNode(root->left,val);

return root;
}

//postorder traversal of the binary search tree


void postorder(struct node *root)
{
if(root == NULL)
return;
//traverse the left subtree
postorder(root->left);

//traverse the right subtree


postorder(root->right);

//visit the root


printf("%d ",root->key);
}

int main()
{
struct node *root = NULL;

root = insertNode(root,100);
root = insertNode(root, 50);
root = insertNode(root, 200);
root = insertNode(root, 10);
root = insertNode(root, 60);
root = insertNode(root, 150);
root = insertNode(root, 300);

postorder(root);

return 0;
}

Output:
10 60 50 150 300 200 100
Deletion in Binary Search Tree:
To delete the given node from the binary search tree(BST), we should follow the
below rules.

1.Leaf Node
If the node is leaf (both left and right will be NULL), remove the node directly
and free its memory.
2.Node with Right Child:
If the node has only right child (left will be NULL), make the node points to the
right node and free the node.
Example
3.Node with Left Child:
If the node has only left child (right will be NULL), make the node points to
the left node and free the node.
Example:
4.Node has both left and right child:
If the node has both left and right child,
1.find the smallest node in the right subtree. say min
2.make node->data = min
3.Again delete the min node.

Example:
Remove function with algorithm explanation:
struct node *removeNode(struct node *root, int val)
{
/*
* If the node becomes NULL, it will return NULL
* Two possible ways which can trigger this case
* 1. If we send the empty tree. i.e root == NULL
* 2. If the given node is not present in the tree.
*/
if(root == NULL)
return NULL;
/*
* If root->key < val. val must be present in the right subtree
* So, call the above remove function with root->right
*/
if(root->key < val)
root->right = removeNode(root->right,val);
/*
* if root->key > val. val must be present in the left subtree
* So, call the above function with root->left
*/
else if(root->key > val)
root->left = removeNode(root->left,val);
/*
* This part will be executed only if the root->key == val
* The actual removal starts from here
*/
else
{
/*
* Case 1: Leaf node. Both left and right reference is NULL
* replace the node with NULL by returning NULL to the calling pointer.
* free the node
*/
if(root->left == NULL && root->right == NULL)
{
free(root);
return NULL;
}
/*
* Case 2: Node has right child.
* replace the root node with root->right and free the right node
*/
else if(root->left == NULL)
{
struct node *temp = root->right;
free(root);
return temp;
}
/*
* Case 3: Node has left child.
* replace the node with root->left and free the left node
*/
else if(root->right == NULL)
{
struct node *temp = root->left;
free(root);
return temp;
}
/*
* Case 4: Node has both left and right children.
* Find the min value in the right subtree
* replace node value with min.
* And again call the remove function to delete the node which has the min
value.
* Since we find the min value from the right subtree call the remove function
with root->right.
*/
else
{
int rightMin = getRightMin(root->right);
root->key = rightMin;
root->right = removeNode(root->right,rightMin);
}

//return the actual root's address


return root;
}
Implementation of Binary Search Tree Deletion (Recursive):
/*
* Program : Binary Search Tree Deletion
* Language : C
*/

#include<stdio.h>
#include<stdlib.h>

struct node
{
int key;
struct node *left;
struct node *right;
};
struct node *getNewNode(int val)
{
struct node *newNode = malloc(sizeof(struct node));
newNode->key = val;
newNode->left = NULL;
newNode->right = NULL;

return newNode;
}

struct node *insert(struct node *root, int val)


{
if(root == NULL)
return getNewNode(val);
if(root->key < val)
root->right = insert(root->right,val);
else if(root->key > val)
root->left = insert(root->left,val);

return root;
}

int getRightMin(struct node *root)


{
struct node *temp = root;

//min value should be present in the left most node.


while(temp->left != NULL){ temp = temp->left;}

return temp->key;
}
struct node *removeNode(struct node *root, int val)
{
/*
* If the node becomes NULL, it will return NULL
* Two possible ways which can trigger this case
* 1. If we send the empty tree. i.e root == NULL
* 2. If the given node is not present in the tree.
*/
if(root == NULL)
return NULL;
/*
* If root->key < val. val must be present in the right subtree
* So, call the above remove function with root->right
*/
if(root->key < val)
root->right = removeNode(root->right,val);
/*
* if root->key > val. val must be present in the left subtree
* So, call the above function with root->left
*/
else if(root->key > val)
root->left = removeNode(root->left,val);
/*
* This part will be executed only if the root->key == val
* The actual removal starts from here
*/
else
{
/*
* Case 1: Leaf node. Both left and right reference is NULL
* replace the node with NULL by returning NULL to the calling pointer.
* free the node
*/
if(root->left == NULL && root->right == NULL)
{
free(root);
return NULL;
}
/*
* Case 2: Node has right child.
* replace the root node with root->right and free the right node
*/
else if(root->left == NULL)
{
struct node *temp = root->right;
free(root);
return temp;
}
/*
* Case 3: Node has left child.
* replace the node with root->left and free the left node
*/
else if(root->right == NULL)
{
struct node *temp = root->left;
free(root);
return temp;
}
/*
* Case 4: Node has both left and right children.
* Find the min value in the right subtree
* replace node value with min.
* And again call the remove function to delete the node which has the min
value.
* Since we find the min value from the right subtree call the remove function
with root->right.
*/
else
{
int rightMin = getRightMin(root->right);
root->key = rightMin;
root->right = removeNode(root->right,rightMin);
}

//return the actual root's address


return root;
}
/*
* it will print the tree in ascending order
*/
void inorder(struct node *root)
{
if(root == NULL)
return;
inorder(root->left);
printf("%d ",root->key);
inorder(root->right);
}

int main()
{
/*
100
/\
50 200
/ \
150 300
*/
struct node *root = NULL;
root = insert(root,100);
root = insert(root,50);
root = insert(root,200);
root = insert(root,150);
root = insert(root,300);

printf("Initial tree :\t");


inorder(root);
printf("\n");
/* remove leaf node 300
100
/\
50 200
/
150
*/
root = removeNode(root,300);
printf("After deletion of 300, the new tree :\t");
inorder(root);
printf("\n");

/* remove root node 100


150
/\
50 200
*/
root = removeNode(root,100);
printf("After deletion of 100, the new tree :\t");
inorder(root);
printf("\n");

return 0;
}

Output:
Initial tree : 50 100 150 200 300
After deletion of 300, the new tree : 50 100 150 200
After deletion of 100, the new tree : 50 150 200
END

You might also like