0% found this document useful (0 votes)
46 views20 pages

Topic 1: Introduction To Binary Search Trees

The document introduces binary search trees. It defines their key properties: nodes with keys less than the parent are in the left subtree, nodes with greater keys are in the right subtree, and each subtree must also be a BST. It provides an example BST and explains that operations like search, minimum and maximum can be done faster on BSTs than regular binary trees due to the ordering. It then discusses searching a key in O(h) time by recursively checking the left or right subtree. Finally, it briefly covers inserting a new node at a leaf and deleting a node, which may involve removing a leaf, copying a child, or copying from an inorder successor.

Uploaded by

Đhîřåj Šäh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views20 pages

Topic 1: Introduction To Binary Search Trees

The document introduces binary search trees. It defines their key properties: nodes with keys less than the parent are in the left subtree, nodes with greater keys are in the right subtree, and each subtree must also be a BST. It provides an example BST and explains that operations like search, minimum and maximum can be done faster on BSTs than regular binary trees due to the ordering. It then discusses searching a key in O(h) time by recursively checking the left or right subtree. Finally, it briefly covers inserting a new node at a leaf and deleting a node, which may involve removing a leaf, copying a child, or copying from an inorder successor.

Uploaded by

Đhîřåj Šäh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 20

Topic 1 : Introduction to Binary Search Trees

Binary Search Tree is a node-based binary tree data structure which has the
following properties:

● The left subtree of a node contains only nodes with keys lesser than or equal
to the node's key.
● The right subtree of a node contains only nodes with keys greater than the
node's key.
● The left and right subtree each must also be a binary search tree.
There must be no duplicate nodes.

Sample Binary Search Tree:

The above properties of Binary Search Tree provide an ordering among keys so that
the operations like search, minimum and maximum can be done fast in comparison
to normal Binary Trees. If there is no ordering, then we may have to compare every
key to search a given key.

Searching a Key
Using the property of Binary Search Tree, we can search for an element in O(h) time
complexity where h is the height of the given BST.

To search a given key in Binary Search Tree, first compare it with root, if the key is
present at root, return root. If the key is greater than the root's key, we recur for the
right subtree of the root node. Otherwise, we recur for the left subtree.
Implementation:
C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// C++ function to search a given key in a given BST
/* Node Structure:

struct Node
{
int key;
Node* left, right;
};
*/
struct node* search(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 is greater than root's key


if (root->key < key)
return search(root->right, key);
// Key is smaller than root's key
return search(root->left, key);
}
Java

Illustration to search a key 6 in the below BST:

1. Start from the root.


2. Compare the key element with root, if less than root, then recur for left
subtree, else recur for right subtree.
3. If an element to search is found anywhere, return true, else return false.

Step 1: Compare 6 with 8.


Since 6 is less than 8,
move to left subtree.
Step 2: Compare 6 with 3.
Since 6 is greater than 3,
move to its right subtree.
Step 3: Comapre 6 with 6.
Node Found.

Insertion of a Key
Inserting a new node in the Binary Search Tree is always done at the leaf nodes to
maintain the order of nodes in the Tree. The idea is to start searching the given node
to be inserted from the root node till we hit a leaf node. Once a leaf node is found,
the new node is added as a child of the leaf node.

For Example:

100 100
/ \ Insert 40 / \
20 500 ---------> 20 500
/ \ / \
10 30 10 30
\
40

Implementation:
C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// C++ program to demonstrate insert
// operation in binary search tree
#include<bits/stdc++.h>
using namespace std;
// Binary Search Tree node
struct node
{
int key;
struct node *left, *right;
};
// A utility function to create a new BST node
struct node *newNode(int item)
{
node *temp = new node;
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
// A utility function to do inorder traversal of BST
void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
cout<<root->key<<" ";
inorder(root->right);
Run
Java
Output:

20 30 40 50 60 70 80

Illustration to insert 2 in the below tree:

1. Start from the root.


2. Compare the element to be inserted with root, if it is less than root, then recur
for left-subtree, else recur for right-subtree.
3. After reaching the end,just insert that node at left(if less than current leaf
node) else right.
Element to be inserted: 2

Step 1: Compare 2 with 8.


Since 2 is less than 8,
move to the left subtree.
Step 2: Compare 2 with 3.
Since 2 is less than 3,
move to its left subtree.
Step 3: Compare 2 with 1.
Since 2 is greater than 1 and also 1 is a leaf node.
Insert 2 as its right child of node 1.

Time Complexity: The worst case time complexity of search and insert operations is
O(h) where h is the height of the Binary Search Tree. In the worst case, we may
have to travel from root to the deepest leaf node. The height of a skewed tree may
become n and the time complexity of search and insert operation may become O(n).
Topic 2 : Deletion in a Binary Search Tree

Given a Binary Search Tree and a node to be deleted. The task is to search that
node in the given BST and delete it from the BST if it is present.

When we delete a node, three cases may arise:

1. Node to be deleted is leaf: Simply remove from the tree.

2. Node to be deleted has only one child: Copy the child to the node and
delete the child.

3. Node to be deleted has two children: Find the successor of the node. Copy
contents of the inorder successor to the node and delete the inorder
successor. Note that inorder predecessor can also be used.

Note: The inorder successor can be obtained by finding the minimum value in the
right child of the node.
Below is the implementation of the above three cases:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// C++ program to demonstrate delete
// operation in binary search tree
#include<bits/stdc++.h>
using namespace std;
// BST Node
struct node
{
int key;
struct node *left, *right;
};
// A utility function to create a new BST node
struct node *newNode(int item)
{
node *temp = new node;
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
// A utility function to do inorder traversal of BST
void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
cout<<root->key<<" ";
inorder(root->right);
}
Run
Java
Output:
Inorder traversal of the given tree
20 30 40 50 60 70 80
Delete 20
Inorder traversal of the modified tree
30 40 50 60 70 80
Delete 30
Inorder traversal of the modified tree
40 50 60 70 80
Delete 50
Inorder traversal of the modified tree
40 60 70 80

Illustration:
Topic 3 : Finding LCA in a Binary Search Tree

We have already seen the definition of LCA and finding LCA of any two nodes in a
Binary Tree.

Let's look at the process of finding LCA in a Binary Search Tree.

Problem: Given values of two values n1 and n2 in a Binary Search Tree, find
the Lowest Common Ancestor (LCA). For Simplicity, you may assume that both the
values exist in the tree.

Consider the below BST:

In the above BST:

LCA of 10 and 14 is 12
LCA of 14 and 8 is 8
LCA of 10 and 22 is 20

The LCA or Lowest Common Ancestor of any two nodes N1 and N2 is


defined as the common ancestor of both the nodes which are closest to them.
That is the distance of the common ancestor from the nodes N1 and N2
should be least possible.

Finding LCA
Since a Binary Search Tree is also a Binary Tree, we can apply the same process of
finding LCA of two nodes in BST as that of binary trees. But finding LCA in a Binary
Tree takes O(N) time complexity.

However, we can solve this problem using BST properties. We can recursively


traverse the BST from the root. The main idea of the solution is, while traversing
from top to bottom, the first node n we encounter with value between n1 and n2,
i.e., n1 <= n <= n2, is LCA of n1 and n2 (assuming that n1 < n2). So just recursively
traverse the BST, if node's value is greater than both n1 and n2 then our LCA lies in
the left subtree of the node, if it is smaller than both n1 and n2, then LCA lies on the
right subtree. Otherwise root is LCA (assuming that both n1 and n2 are present in
BST).

Below is the implementation of this approach:


C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// A recursive CPP program to find
// LCA of two nodes n1 and n2.
#include <bits/stdc++.h>
using namespace std;
class node
{
public:
int data;
node* left, *right;
};
// Function to find LCA of n1 and n2.
// The function assumes that both
// n1 and n2 are present in BST
node *lca(node* root, int n1, int n2)
{
if (root == NULL) return NULL;
// If both n1 and n2 are smaller
// than root, then LCA lies in left
if (root->data > n1 && root->data > n2)
return lca(root->left, n1, n2);
// If both n1 and n2 are greater than
// root, then LCA lies in right
if (root->data < n1 && root->data < n2)
return lca(root->right, n1, n2);
Run
Java
Output:
LCA of 10 and 14 is 12
LCA of 14 and 8 is 8
LCA of 10 and 22 is 20

The time complexity of the above solution is O(h) where h is the height of the tree.
Also, the above solution requires O(h) extra space in function call stack for recursive
function calls. We can avoid extra space using an iterative solution.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Function to find LCA of n1 and n2.
The function assumes that both
n1 and n2 are present in BST */
struct node *lca(struct node* root, int n1, int n2)
{
while (root != NULL)
{
// If both n1 and n2 are smaller than root,
// then LCA lies in left subtree
if (root->data > n1 && root->data > n2)
root = root->left;
// If both n1 and n2 are greater than root,
// then LCA lies in the right subtree
else if (root->data < n1 && root->data < n2)
root = root->right;
else break;
}
return root;
}
Topic 4 : Introduction to AVL Tree

AVL tree is a self-balancing Binary Search Tree (BST) where the difference between
heights of left and right subtrees cannot be more than one for all nodes.

An Example Tree that is an AVL Tree:

The above tree is AVL because differences between heights of left and right
subtrees for every node is less than or equal to 1.

An Example Tree that is NOT an AVL Tree:

The above tree is not AVL because differences between heights of left and right
subtrees for 8 and 18 is greater than 1.
Why AVL Trees?
Most of the BST operations (e.g., search, max, min, insert, delete.. etc) take O(h)
time where h is the height of the BST. The cost of these operations may become
O(n) for a skewed Binary tree. If we make sure that the height of the tree remains
O(Logn) after every insertion and deletion, then we can guarantee an upper bound of
O(Logn) for all these operations. The height of an AVL tree is always O(Logn) where
n is the number of nodes in the tree.

Insertion
To make sure that the given tree remains AVL after every insertion, we must
augment the standard BST insert operation to perform some re-balancing. Following
are two basic operations that can be performed to re-balance a BST without violating
the BST property (keys(left) < key(root) < keys(right)).

1. Left Rotation
2. Right Rotation

T1, T2 and T3 are subtrees of the tree


rooted with y (on the left side) or x (on
the right side)

Keys in both of the above trees follow the


following order:
keys(T1) < key(x) < keys(T2) < key(y) < keys(T3)

So BST property is not violated anywhere.

Steps to follow for insertion: Let the newly inserted node be w.

1. Perform standard BST insert for w.


2. Starting from w, travel up and find the first unbalanced node. Let z be the first
unbalanced node, y be the child of z that comes on the path from w to z and x
be the grandchild of z that comes on the path from w to z.
3. Re-balance the tree by performing appropriate rotations on the subtree rooted
with z. There can be 4 possible cases that need to be handled as x, y and z
can be arranged in 4 ways. Following are the possible 4 arrangements:

o y is left child of z and x is left child of y (Left Left Case)


o y is left child of z and x is right child of y (Left Right Case)
o y is right child of z and x is right child of y (Right Right Case)
o y is right child of z and x is left child of y (Right Left Case)

Following are the operations to be performed in the above mentioned 4 cases. In all
of the cases, we only need to re-balance the subtree rooted with z and the complete
tree becomes balanced as the height of subtree (After appropriate rotations) rooted
with z becomes the same as it was before insertion.

a) Left Left Case


T1, T2, T3 and T4 are subtrees.

b) Left Right Case

c) Right Right Case

d) Right Left Case


Insertion Examples:
Time Complexity: The rotation operations (left and right rotate) take constant time
as only a few pointers are being changed there. Updating the height and getting the
balance factor also takes constant time. So the time complexity of AVL insert
remains the same as BST insert which is O(h) where h is the height of the tree.
Since the AVL tree is balanced, the height is O(Logn). So the time complexity of AVL
insert is O(Logn).

You might also like