Unit IV
Unit IV
struct node
{
int data;
struct node *leftchild;
struct node *rightchild;
}
Important Terms
Following are the important terms with respect to tree.
Tree Terminologies
Root
● In a tree data structure, the root is the first node of the tree. The root node is
the initial node of the tree in data structures.
● In the tree data structure, there must be only one root node.
Edge
● In a tree in data structures, the connecting link of any two nodes is called the
edge of the tree data structure.
● In the tree data structure, N number of nodes connecting with N -1 number of
edges.
Parent
In the tree in data structures, the node that is the predecessor of any node is known as a
parent node, or a node with a branch from itself to any other successive node is called
the parent node.
Child
● The node, a descendant of any node, is known as child nodes in data
structures.
● In a tree, any number of parent nodes can have any number of child nodes.
● In a tree, every node except the root node is a child node.
Siblings
In trees in the data structure, nodes that belong to the same parent are called siblings.
Leaf
● Trees in the data structure, the node with no child, is known as a leaf node.
● In trees, leaf nodes are also called external nodes or terminal nodes.
Internal nodes
● Trees in the data structure have at least one child node known as internal
nodes.
● In trees, nodes other than leaf nodes are internal nodes.
● Sometimes root nodes are also called internal nodes if the tree has more than
one node.
Degree
● In the tree data structure, the total number of children of a node is called the
degree of the node.
● The highest degree of the node among all the nodes in a tree is called the
Degree of Tree.
Level
In tree data structures, the root node is said to be at level 0, and the root node's children
are at level 1, and the children of that node at level 1 will be level 2, and so on.
Height
● In a tree data structure, the number of edges from the leaf node to the
particular node in the longest path is known as the height of that node.
● In the tree, the height of the root node is called "Height of Tree".
● The tree height of all leaf nodes is 0.
●
Depth
● In a tree, many edges from the root node to the particular node are called the
depth of the tree.
● In the tree, the total number of edges from the root node to the leaf node in the
longest path is known as "Depth of Tree".
● In the tree data structures, the depth of the root node is 0.
Path
● In the tree in data structures, the sequence of nodes and edges from one node
to another node is called the path between those two nodes.
● The length of a path is the total number of nodes in a path.zx
Subtree
In the tree in data structures, each child from a node shapes a sub-tree recursively and
every child in the tree will form a sub-tree on its parent node.
Binary Tree
A binary tree in DSA (Data Structures and Algorithms) is a way to organize data in a hierarchical
structure. In a binary tree, each node has at most two children, called the left child and the right
child. The topmost node is called the root, and the nodes with no children are called leaves.
The basic idea of a binary tree is to have a parent-child relationship between nodes. Each node
can have a left and a right child, and this pattern continues down the tree. This structure makes
it easy to organize and find data quickly.
Types of Binary Tree in Data Structure
Let’s understand what are the different types of binary tree with examples:
A full binary tree is a tree where every node has either 0 or 2 children.
Example:
A complete binary tree is a tree where all levels are fully filled except possibly the last level,
which is filled from left to right.
Example:
A perfect binary tree is a tree where all internal nodes have exactly two children and all leaf
nodes are at the same level.
Example:
A balanced binary tree is a tree where the height of the left and right subtrees of any node
differ by at most one.
Example:
A degenerate binary tree is a tree where each parent node has only one child. This makes
the tree look like a linked list.
Example:
Properties of Binary Tree (Height and Level Start with 0)
Basic Terminology
● **Node**: A basic unit containing data and links to child nodes.
● **Root**: The topmost node of the binary tree.
● **Child**: A node directly connected to another node when moving away from the root.
● **Parent**: A node that has a link to children nodes.
● **Leaf Node**: A node with no children.
● **Level**: The level of a node is the number of edges on the path from the root to that node.
Root is at level 0.
● **Height**: The height of a tree is the number of edges on the longest downward path from the
root to a leaf. A single node (root only) tree has height 0.
Important Properties
● Example:
● Example:
● Example:
● Example:
Important Notes
● **Perfect Binary Tree**: All internal nodes have 2 children and all leaves are at the same level.
● **Complete Binary Tree**: All levels are completely filled except possibly the last, which is filled
from left to right.
● **Skewed Binary Tree**: Every parent has only one child.
● - Left-skewed: each node has only a left child.
● - Right-skewed: each node has only a right child.
Example Tree
Consider this binary tree:
A
/ \
B C
/ \
D E
● Levels:
● - Level 0: A
● - Level 1: B, C
● - Level 2: D, E
In this method, each node is represented as a structure or object with three fields:
This method is space-efficient and ideal for dynamic binary trees where the number of nodes is
not fixed.
Advantages:
● It can easily grow or shrink as needed, so it uses only the memory it needs.
● Adding or removing nodes is straightforward and requires only pointer adjustments.
● Only uses memory for the nodes that exist, making it efficient for sparse trees.
Disadvantages:
● Needs extra memory for pointers.
● Finding a node can take longer because you have to start from the root and follow
pointers.
Example Code:
struct Node {
int data;
struct Node* left;
struct Node* right;
};
// Creating a node in main or a function
Node* createNode(int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
2. Array Representation
useful when the tree is complete (all levels are fully filled except possibly
Or
In this method, a binary tree is stored in a linear array. The root node is
· Parent Index = (i - 1) / 2
Example:
A
/ \
B C
/ \
D E
Binary Tree
A binary tree is a data structure in which each node has at most two
children, referred to as the left child and the right child.
Traversing a binary tree means visiting all the nodes in a specific order.
There are three main types of depth-first traversal methods:
If a binary tree is traversed in-order, the output will produce sorted key
values in an ascending order.
Steps:
Algorithm
Until all nodes are traversed −
Example 1:
A
/\
B C
/\
D E
Inorder: D B E A C
Example 2:
1
/\
2 3
/\
4 5
Inorder: 4 2 5 1 3
We start from A, and following pre-order traversal, we first visit A itself and
then move to its left subtree B. B is also traversed pre-order. The process
goes on until all the nodes are visited. The output of pre-order traversal of
this tree will be −
A→B→D→E→C→F→G
Steps:
Algorithm
Until all nodes are traversed −
Example 1:
A
/\
B C
/\
D E
Preorder: A B D E C
Example 2:
1
/\
2 3
/\
4 5
Preorder: 1 2 4 5 3
Steps:
Algorithm
Until all nodes are traversed −
Example 1:
A
/\
B C
/\
D E
Postorder: D E B C A
Example 2:
1
/\
2 3
/\
4 5
Postorder: 4 5 2 3 1
Diagram:
Binary Tree:
A
/\
B C
/\
D E
Summary Table:
Traversal Order
Type
Inorder DBEAC
Preorder ABDEC
Postorder DEBCA
Practice Examples:
Example 3:
F
/\
D G
/\
B E
/
A
● Inorder: A B D E F G
● Preorder: F D B A E G
● Postorder: A B E D G F
Example 4:
M
/\
L Q
/\
N R
● Inorder: L M N Q R
● Preorder: M L Q N R
● Postorder: L N R Q M
Example:
Level-order Traversal: 1, 2, 3, 4, 5
Steps:
● Visit the root: 1
● Visit the nodes at the next level: 2, 3
● Visit the nodes at the next level: 4, 5
1. Insertion
Insertion involves adding a new node to the binary tree. In a binary tree, a new node
is usually inserted at the first available position in level order to maintain the
completeness of the tree.
Example:
Let's insert the value 6 into the following binary tree:
2. Deletion
Deletion involves removing a node from the binary tree. In a binary tree, the node to
be deleted is replaced by the deepest and rightmost node to maintain the tree's
structure.
Example:
Let's delete the value 3 from the following binary tree:
3. Search
Searching involves finding a node with a given value in the binary tree. The search
operation can be implemented using any traversal method (in-order, pre-order,
post-order, or level-order).
Example:
Let's search for the value 5 in the following binary tree:
Using level-order traversal:
● Visit node 1
● Visit node 2
● Visit node 3
● Visit node 4
● Visit node 5 (found)
4. Traversal
Traversal involves visiting all the nodes in the binary tree in a specific order. The
main traversal methods are in-order, pre-order, post-order, and level-order.
Example:
Consider the following binary tree:
● In-order Traversal (Left, Root, Right): 4, 2, 5, 1, 3
● Pre-order Traversal (Root, Left, Right): 1, 2, 4, 5, 3
● Post-order Traversal (Left, Right, Root): 4, 5, 2, 3, 1
● Level-order Traversal (Breadth-First): 1, 2, 3, 4, 5
The main idea behind setting such a structure is to make the inorder and preorder traversal of a
binary tree faster without using any additional Data structure (e.g. auxiliary stack) or memory for
its traversal.
What is the need for a Threaded Binary Tree?
●
struct Node{
int value;
Node* left;
Node* right;
bool rightThread;
}
struct Node{
int value;
Node* left;
Node* right;
bool rightThread;
bool leftThread;
}
Here, the leftThread and rightThread boolean variables help us to differentiate
whether the left/right pointer stores the in-order predecessor/successor or left child/right
child.
Let’s look at an example to understand this.
This is how a Double-Threaded Binary Tree looks like. You can observe here that node value 40
have no left and right child. So, its left pointer points to its in-order predecessor (node value 30)
and it's right pointer points towards its in-order successor (node value 50). Similarly, the other
nodes of this tree with a left/right null pointer refers to their in-order predecessor/successor
using threads.
1. Initialize: Set current to the leftmost node of the tree using the
Leftmost(root) function
2. Traversal Loop: While current is not null, repeat the following steps
3. Process Node: Process the current node by performing the desired action
using the ProcessNode function
○ Else: Set current to the leftmost node in the right subtree using
Leftmost(current.rightChild)
6. Finish: The algorithm completes when all nodes in the threaded binary tree
are processed
Advantages of Threaded Binary Tree
Let’s discuss some advantages of a Threaded Binary tree.
○ No need for stacks or recursion: Unlike binary trees, threaded binary trees
do not require a stack or recursion for their traversal.
○ Optimal memory usage: Another advantage of threaded binary tree data
structure is that it decreases memory wastage. In normal binary trees,
whenever a node’s left/right pointer is NULL, memory is wasted. But with
threaded binary trees, we are overcoming this problem by storing its inorder
predecessor/successor.
○ Time complexity: In-order traversal in a threaded binary tree is fast
because we get the next node in O(1) time than a normal binary tree that
takes O(Height). But insertion and deletion operations take more time for the
threaded binary tree.
○ Backward traversal: In a double-threaded binary tree, we can even do a
backward traversal.
Heap
Introduction
A heap is a special type of tree-based data structure where the tree is a complete binary
tree. They follow a special rule: in every node, the value must be either bigger than or
the same as its children's values (this is called a max-heap) or smaller than or equal to
its children's values (this is called a min-heap). This makes heaps perfect for creating
priority queues, where you always need quick access to the largest or smallest element,
which is kept at the top of the tree. Heaps are used in many popular algorithms like
Dijkstra's Shortest Path and Heap Sort.
📌 Definition
● A Heap is a special tree-based data structure that satisfies the heap property.
○ Max Heap: The value of each node is greater than or equal to the values
of its children.
○ Min Heap: The value of each node is less than or equal to the values of
its children.
🌳 Structure
● A heap is a nearly complete binary tree.
● All levels are fully filled except possibly the last, which is filled from left to
right.
🔄 Heap Property
● The highest-priority (max or min) element is always at the top (root) of the
heap.
As mentioned earlier, a heap is a complete binary tree. This means that all levels of the
tree are fully filled, except possibly the last level, which is filled from left to right. This
property allows heaps to be efficiently stored in an array.
In an array representation of a heap, the first element (index 0) is the root of the heap.
For any element at index i:
The heap property (either max-heap or min-heap) is what distinguishes a heap from a
regular binary tree. In a max-heap, for any given node C, if P is a parent node of C, then
the key (the value) of P is greater than or equal to the key of C. In a min-heap, the key
of P is less than or equal to the key of C.
This property is crucial for efficient insertion & deletion operations, as it allows us to
maintain the heap structure while only comparing a node with its parent or children.
Another important property of heaps is that they are not sorted structures. The only
guarantee is that the root element is either the maximum (in a max heap) or the
minimum (in a min-heap). The other elements are not in any particular order.
Types of Heaps
There are two main types of heaps: max heaps & min heaps.
1. Max Heap: In a max heap, the key at the root node must be the largest among all the
keys present in the heap. The same property must be recursively true for all sub-trees in
the binary tree.
2. Min Heap: In a min heap, the key at the root node must be the smallest among all the
keys present in the heap. The same property must be recursively true for all sub-trees in
the binary tree.
The min-heap property is useful for algorithms like Dijkstra's Shortest Path, while the
max-heap property is useful for algorithms like Heap Sort.
It's important to note that there is no ordering between siblings in a heap - the only
requirement is that the parent node must be greater than (in a max heap) or less than
(in a min-heap) both of its children.
Heaps are usually implemented with the help of arrays, with the array indices used to
implicitly represent the tree structure based on the parent-child relationships. For a node
at index i, its children are at indices 2i+1 & 2i+2, while its parent (if any) is at index
floor((i-1)/2).
Heap Operations
Operations supported by min – heap and max – heap are same. The difference is just that
min-heap contains minimum element at root of the tree and max – heap contains maximum
element at the root of the tree.
Heapify:
It is the process to rearrange the elements to maintain the property of heap data structure. It is
done when root is removed (we replace root with the last node and then call heapify to ensure
that heap property is maintained) or heap is built (we call heapify from the last internal node to
root) to make sure that the heap property is maintained. This operation also takes O(log n) time.
For max-heap, it makes sure the maximum element is the root of that binary tree and all
descendants also follow the same property.
For min-heap, it balances in such a way that the minimum element is the root and all
descendants also follow the same property.
Insertion:
1. Insertion
Examples:
8
/ \
4 5
/ \
1 2
After repeatedly comparing with the parent nodes and swapping if required, the final heap will
be look like this
10
/ \
4 8
/ \ /
1 25
Deletion:
○ The new root is compared with its children and swapped down if
needed (heapify-down).
If we delete the element from the heap it always deletes the root element of the tree and
replaces it with the last element of the tree.
Since we delete the root element from the heap it will distort the properties of the heap so we
need to perform heapify operations so that it maintains the property of the heap.
Example:
Now if we delete 15 into the heap it will be replaced by leaf node of the tree for temporary.
3
/ \
5 7
/
2
It finds the maximum element or minimum element for max-heap and min-heap respectively
and as we know minimum and maximum elements will always be the root node itself for
min-heap and max-heap respectively. It takes O(1) time.
removeMin or removeMax:
This operation returns and deletes the maximum element and minimum element from the
max-heap and min-heap respectively. In short, it deletes the root element of the heap binary
tree.
Binary Search Tree(BST)
Binary search tree is a data structure that quickly allows us to maintain a
sorted list of numbers.
● It is called a binary tree because each tree node has a maximum of two
children.
● It is called a search tree because it can be used to search for the
presence of a number in O(log(n)) time.
The properties that separate a binary search tree from a regular binary tree is
1. All nodes of left subtree are less than the root node
2. All nodes of right subtree are more than the root node
3. Both subtrees of each node are also BSTs i.e. they have the above two
properties
A tree having a right subtree with one value smaller than the root is shown to demonstrate that it is
not a valid binary search tree
The binary tree on the right isn't a binary search tree because the right
subtree of the node "3" contains a value smaller than it.
There are two basic operations that you can perform on a binary search tree:
Search Operation
The algorithm depends on the property of BST that if each left subtree has
values below root and each right subtree has values above the root.
If the value is below the root, we can say for sure that the value is not in the
right subtree; we need to only search in the left subtree and if the value is
above the root, we can say for sure that the value is not in the left subtree; we
need to only search in the right subtree.
Definition:
📌 Algorithm (Pseudocode):
Function Search(root, value):
If root is NULL:
Return false
If value == root.data:
Return true
If value < root.data:
Return Search(root.left, value)
Else:
Return Search(root.right, value)
OR
Algorithm:
If root == NULL
return NULL;
If number == root->data
return root->data;
If number < root->data
return search(root->left)
If number > root->data
return search(root->right)
If the value is not found, we eventually reach the left or right child of a leaf
node which is NULL and it gets propagated and returned.
Insert Operation
Inserting a value in the correct position is similar to searching because we try
to maintain the rule that the left subtree is lesser than root and the right
subtree is larger than root.
We keep going to either right subtree or left subtree depending on the value
and when we reach a point left or right subtree is null, we put the new node
there.
Insertion in a Binary Tree means adding a new node to the tree in such a way
that the structure of the tree remains a Binary Tree, i.e., each node has at
most two children.
In Binary Search Tree (BST) specifically, insertion follows an ordered rule:
- Left subtree has nodes with values less than the root.
- Right subtree has nodes with values greater than the root.
Algorithm:
OR
If node == NULL
return createNode(data)
if (data < node->data)
node->left = insert(node->left, data);
else if (data > node->data)
node->right = insert(node->right, data);
return node;
🔢 Step-by-step Construction:
1. Insert 50:
→ Tree is empty, so 50 becomes the root.
50
2. Insert 30:
→ 30 < 50 → insert to the left of 50.
50
/
30
3. Insert 70:
→ 70 > 50 → insert to the right of 50.
50
/ \
30 70
4. Insert 20:
→ 20 < 50 → go left → 20 < 30 → insert to the left of 30.
50
/ \
30 70
/
20
5. Insert 40:
→ 40 < 50 → go left → 40 > 30 → insert to the right of 30.
50
/ \
30 70
/ \
20 40
6. Insert 60:
→ 60 > 50 → go right → 60 < 70 → insert to the left of 70.
50
. / \
30 70
/ \ /
20 40 60
7. Insert 80:
→ 80 > 50 → go right → 80 > 70 → insert to the right of 70.
50
. / \
30 70
/ \ / \
20 40 60 80
In a Binary Search Tree (BST), each node has at most two children, and the
left child contains a value less than the parent node, while the right child
contains a value greater than the parent node. Deletion in a BST is a bit more
complex than insertion because the tree needs to maintain its sorted property
even after the node has been removed.
The key challenge in deleting a node from a BST is ensuring that the tree
maintains its properties after the deletion. Let’s explore each of these cases in
detail.
A leaf node is a node that has no children. This is the simplest case of
deletion because there are no structural changes required to the tree other
than removing the node.
3. Update the parent’s pointer to null, as the node no longer exists.
Example:
Consider the following tree:
50
/ \
30 70
/ \ / \
20 40 60 80
50
/ \
30 70
\ / \
40 60 80
When a node has only one child, the process is a bit more complex, but still
straightforward. Instead of simply removing the node, we replace it with its
child.
2. If the node has only one child, replace the node with its child.
50
/ \
30 70
\ / \
40 60 80
If we delete node 30, which has only one child (40), the tree becomes:
50
/ \
40 70
/ \
60 80
When a node has two children, the process of deletion is more complex. In
this case, we need to find a replacement for the node that preserves the
properties of the BST. This replacement is typically the inorder successor or
inorder predecessor of the node.
● The inorder successor is the smallest node in the right subtree of the
node.
● The inorder predecessor is the largest node in the left subtree of the
node.
The inorder successor is usually chosen for deletion because it’s guaranteed
to be greater than all the nodes in the left subtree but less than all the nodes
in the right subtree.
2. Find the inorder successor of the node (smallest node in the right
subtree).
Example:
Consider the following tree:
50
/ \
30 70
/ \ / \
20 40 60 80
If we delete node 50, which has two children, we find the inorder successor.
The inorder successor of 50 is 60 (the smallest node in the right subtree). So
we replace 50 with 60, and then we delete 60 from its original position.
60
/ \
30 70
/ \ \
20 40 80
Time Complexity
AVL Tree
Definition
An AVL tree is a type of self-balancing binary search tree (BST). The key property of an AVL
tree is that for every node, the difference between the heights of the left and right subtrees
(known as the balance factor) is at most 1. This ensures that the tree remains balanced and
operations like insertion, deletion, and search can be performed in O(log n) time.
Theory
In a regular binary search tree (BST), the height of the left and right subtrees can differ
significantly, leading to unbalanced trees. In such unbalanced trees, operations such as
insertion and deletion could take O(n) time, where n is the number of nodes in the tree.
● Balance Factor (BF) of any node is the difference between the heights of its left and
right subtrees.
If the balance factor of any node becomes greater than 1 or less than -1, the tree is rebalanced
using rotations.
Balance Factor
● Balance Factor = 0: The node is balanced (both subtrees have equal height).
● Balance Factor = 1: The left subtree is one level taller than the right subtree.
● Balance Factor = -1: The right subtree is one level taller than the left subtree.
● Balance Factor > 1: The node is left-heavy and requires a rotation to the right.
● Balance Factor < -1: The node is right-heavy and requires a rotation to the left.
Avl tree
Consider the following AVL tree:
●
This AVL tree is balanced because the balance factors of all nodes are within the range of -1 to 1.
There are four types of rotations: Left Rotation, Right Rotation, Left-Right Rotation, and
Right-Left Rotation. Each rotation helps to rebalance the tree when a node becomes
unbalanced.
1. Left Rotation
A left rotation is performed when a node's right subtree is heavier than its left subtree
(balance factor < -1). This rotation shifts the balance to the left.When a node is added
into the right subtree of the right subtree, if the tree gets out of balance, we
2. Right Rotation A right rotation is performed when a node's left subtree is heavier than its
right subtree (balance factor > 1). This rotation shifts the balance to the right.If a node is added
to the left subtree of the left subtree, the AVL tree may get out of balance,
we do a single right rotation.
The main operations on an AVL tree include insertion, deletion, and search. After each insertion or
deletion, the tree may become unbalanced, requiring rebalancing through rotations.
Insertion is similar to insertion in a regular binary search tree, but after every insertion, the tree
needs to be rebalanced.
4. If the balance factor of any node is outside the range [-1, 1], perform rotations to restore
balance.
●
Example of Insertion:
Algorithm:
● Perform a standard BST insertion.
● Update the height of the current node.
● Calculate the balance factor of the current node.
● Perform rotations if the node becomes unbalanced.
Example:
2. Deletion in AVL Tree
Deletion in an AVL tree follows similar steps as in a regular BST deletion. However, after deletion,
we need to check the balance factor and perform rotations if necessary.
4. If the balance factor of any node is outside the range [-1, 1], perform the appropriate rotation.
Algorithm:
● Perform a standard BST deletion.
● Update the height of the current node.
● Calculate the balance factor of the current node.
● Perform rotations if the node becomes unbalanced.
Example:
Delete key 20 from the AVL tree:
3. Searching
Searching in an AVL tree is similar to searching in a binary search tree (BST). Since AVL
trees are balanced, searching is efficient with a time complexity of O(log n).
Algorithm:
● Start from the root node.
● Compare the target key with the key of the current node.
● If the target key is equal to the current node's key, return the node.
● If the target key is less than the current node's key, move to the left child.
● If the target key is greater than the current node's key, move to the right child.
● Repeat steps 2-5 until the target key is found or the leaf node is reached.
Example:
Search for key 20 in the AVL tree:
Now the tree is balanced, with all balance factors within the range [-1, 1].
Algorithm:
● Start at the root (or any arbitrary node) and mark it as visited.
● Explore each adjacent node recursively that has not been visited yet.
● Repeat the process until all nodes are visited.
Steps:
● Initialize a stack and push the starting node onto the stack.
● While the stack is not empty:
● Pop a node from the stack.
● If the node has not been visited:
● Mark the node as visited.
● Push all adjacent unvisited nodes onto the stack.
Example:
Consider the following graph:
Traversal Order: A, C, E, B, D
Breadth First Search (BFS) algorithm starts at the tree root and explores all
nodes at the present depth prior to moving on to the nodes at the next
depth level.
Algorithm:
● Start at the root (or any arbitrary node) and mark it as visited.
● Explore each adjacent node level by level.
● Repeat the process until all nodes are visited.
Steps:
● Initialize a queue and enqueue the starting node.
● While the queue is not empty:
● Dequeue a node from the queue.
● If the node has not been visited:
● Mark the node as visited.
● Enqueue all adjacent unvisited nodes.
Example:
Consider the same graph:
Traversal Order: A, B, C, D, E