DS Unit 3
DS Unit 3
Tree ADT – Tree Traversals – Binary Tree ADT – Expression trees – Binary Search Tree
ADT – AVL Trees – Priority Queue (Heaps) – Binary Heap.
Trees ADT
A tree is a finite set of one or more nodes such that -
i) There is a specially designated node called root.
ii) The remaining nodes are partitioned into n >= 0 disjoint sets T1, T2, T3...Tn
T1,T2T3, ...T are called the sub-trees of the root.
The concept of tree is represented by following Fig. 4.1.1.
Various operations that can be performed on the tree data structure are -
1. Creation of a tree.
2. Insertion of a node in the tree as a child of desired node.
3. Deletion of any node(except root node) from the tree.
4. Modification of the node value of the tree.
5. Searching particular node from the tree.
Basic Terminologies
Let us get introduced with some of the definitions or terms which are normally used.
1. Root
Root is a unique node in the tree to which further subtrees are attached. For above given tree,
node 10 is a root node.
2. Parent node
The node having further sub-branches is called parent node. In Fig. 4.2.2 the 20 is parent node of
40, 50 and 60.
3. Child nodes
The child nodes in above given tree are marked as shown below
4. Leaves
These are the terminal nodes of the tree.
For example -
6. Degree of tree
The maximum degree in the tree is degree of tree.
7. Level of the tree
The root node is always considered at level zero.
The adjacent nodes to root are supposed to be at level 1 and so on.
• In other words, the full binary tree is a binary tree in which all the nodes have two children
except the leaf node.
Complete Binary Tree
• The complete binary tree is a binary in which all the levels are completely filled except the last
level which is filled from left.
• There are two points to be remembered
1) The leftmost side of the leaf node must always be filled first.
2) It is not necessary for the last leaf node to have right sibling.
• Note that in above representation, Tree 1 is a complete binary tree in which all the levels are
completely filled, whereas Tree 2 is also a complete binary tree in which the last level is filled
from left to right but it is incompletely filled.
Representation of Tree
There are two ways of representing the binary tree.
1. Sequential representation
2. Linked representation.
Let us see these representations one by one.
1. Sequential representation of binary trees or array representation :
Each node is sequentially arranged from top to bottom and from left to right. Let us understand
this matter by numbering each node. The numbering will start from root node and then remaining
nodes will give ever increasing numbers in level wise direction. The nodes on the same level will
be numbered from left to right. The numbering will be as shown below.
Now, observe Fig. 4.5.1 carefully. You will get a point that a binary tree of depth n having 2 n-1
number of nodes. In Fig. 4.5.1 the tree is having the depth 4 and total number of nodes are 15.
Thus remember that in a binary tree of depth n there will be maximum 2 n-1 nodes. And so if we
know the maximum depth of the tree then we can represent binary tree using arrays data
structure. Because we can then predict the maximum size of an array that can accommodate the
tree.
Thus array size can be >=n. The root will be at index 0. Its left child will be at index 1, its right
child will be at index 2 and so on. Another way of placing the elements in the array is by
applying the formula as shown below-
• When n = 0 the root node will placed at 0th location
•Parent(n) = floor(n-1)/2
•Left(n) = (2n+1)
• Right(n) = (2n+2).
As these drawbacks are there with this sequential type of representation, we will search for more
flexible representation. So instead of array we will make use of linked list to represent the tree.
2. Linked representation or node representation of binary trees
In binary tree each node will have left child, right child and data field.
The left child is nothing but the left link which points to some address of left subtree whereas
right child is also a right link which points to some address of right subtree. And the data field
gives the information about the node. Let us see the 'C' structure of the node in a binary tree.
typedef struct node
{
int data;
struct node *left;
struct node *right;
}bin;
The tree with Linked representation is as shown below -
Tree Traversal
Algorithm:
1. If tree is not empty then
a. traverse the left subtree in inorder
b. visit the root node
c. traverse the right subtree in inorder
The recursive routine for inorder traversal is as given below to
void inorder(node *temp)
{
if(temp!= NULL)
{
inorder(temp->left);
printf("%d",temp->data);
inorder(temp->right);
}
}
2) Preorder Traversal :
In this type of traversal, the parent node or root node is visited first; then left node and finally
right node will be visited.
For example
Algorithm:
1. If tree is not empty then
a. visit the root node
b. traverse the left subtree in preorder
c. traverse the right subtree in preorder
The recursive routine for preorder traversal is as given below.
void preorder(node *temp)
{
if(temp!= NULL)
{
printf("%d",temp->data);
preorder(temp->left);
preorder(temp->right);
}
}
3) Postorder Traversal :
In this type of traversal, the left node is visited first, then right node and finally parent node is
visited.
For example
Algorithm:
1. If tree is not empty then
a. traverse the left subtree in postorder
b. traverse the right subtree in postorder
c. visit the root node
The recursive routine for postorder traversal is as given below.
void postorder(node *temp)
{
if(temp!= NULL)
{
postorder(temp->left);
postorder(temp->right);
printf("%d",temp->data);
}
}
Ex. 4.6.1: Write inorder, preorder and postorder traversal for the following tree:
Sol. :
Inorder 8 10 11 30 20 25 40 42 45 60 50 55
Preorder 40 30 10 8 11 25 20 50 45 42 60 55
Postorder 8 11 10 20 25 30 42 60 45 55 50 40.
Expression Trees
Definition: An expression tree is a binary tree in which the operands are attached as leaf nodes
and operators become the internal nodes.
For example -
Now we will read each symbol from left to right one character at a time. If we read an operand
then we will make a node of it and push it onto the stack. If we read operator then pop two nodes
from stack, the first popped node will be attached as right child to operator node and second
popped node will be attached as a left child to operator node. For the above given expression let
us build a tree.
As now we read '\0', pop the content of stack. The node which we will get is the root node of an
expression tree.
Let us implement it
Ex. 4.7.1 Program for creating an expression tree and printing it using an inorder
traversal.
Sol. :
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
#include <ctype.h>
#define size 20
typedef struct node
{
char data;
struct node *left;
struct node *right;
}btree;
/*stack stores the operand nodes of the tree*/
btree *stack[size];
int top;
void main()
{
btree *root;
char exp[80]; /* exp stores postfix expression */
btree *create(char exp[80]);
void display(btree *root);
clrscr();
printf("Enter the postfix expression\n");
scanf("%s",exp);
top = -1; /* Initialise the stack */
root = create(exp);
printf("\n The Tree is created...\n");
printf("\n The inorder traversal of it is \n");
display(root);
getch();
}
btree* create(char exp[])
{
btree *temp;
int pos;
char ch;
void push(btree *);
btree *pop();
pos = 0;
ch = exp[pos];
while (ch!= '\0')
{
/* Create a new node */
temp = (btree *)malloc(sizeof(btree));
temp -> left = temp -> right = NULL;
temp -> data = ch;
if (isalpha(ch) ) /* is it a operand */
push (temp); /* push operand */
else if (ch=='+' || ch=='-'||ch=='*' || ch=='/')
{
/* it is operator, so pop two nodes from stack
set first node as right child and
set second as left child and push the
operator node on to the stack
*/
temp->right = pop();
temp ->left = pop();
push(temp);
}
else
printf("Invalid character in expression\n");
pos ++;
ch= exp[pos]; /* Read next character */
}
temp = pop();
return(temp);
}
void push(btree *Node)
{
if (top+1 >= size)
printf("Error: Stack is Full\n");
top++;
stack[top] = Node;
}
btree* pop()
{
btree *Node;
if (top == -1)
printf("Error: Stack is Empty\n");
Node = stack[top];
top--;
return(Node);
}
void display(btree *root)
{
btree *temp;
temp = root;
if (temp!= NULL)
{
display(temp->left);
printf("%c", temp->data);
display(temp->right);
}
}
Output
Enter the postfix expression
ab+cd-*
The Tree is created...
The inorder traversal of it is a + b * c-d
Applications of Trees
Various applications of trees are -
1. Binary search tree
2. Expression tree
3. Threaded binary tree.
Binary search tree is a binary tree in which the nodes are arranged in specific order. That means
the values at left subtree are less than the root node value. Similarly the values at the right
subtree are greater than the root node. Fig. 4.9.1 represents the binary search tree.
The binary search tree is based on binary search algorithm.
In the Fig. 4.9.2 if we want to insert 23. Then we will start comparing 23 with value of root node
i.e. 6. As 23 is greater than 10, we will move on right onto ONA 2.25 015 subtree. Now we will
compare 23 with 20 and move right, compare 23 with 22 and move right. Now compare 23 with
24 but it is less than 24. We will move on left branch of 24. But as there is NULL node as left
child of 24, we can attach 23 as left child of 24.
From the above tree, we want to delete the node having value 6 then we will set left pointer of its
parent node as NULL. That is left pointer of node having value 8 is set to NULL.
There are three types of threading possible - Inorder, preorder and postorder threading.
C structure
typedef struct thread
{
int data;
int lth,rth;
struct thread *left;
struct thread *right;
}Th;
The basic idea in inorder threading is that the left thread should point to the predecessor and the
right thread points to the successor. Here we are assuming the head node as the starting node and
the root node of the tree is attached to left of head node which is as shown in Fig. 4.10.1.
Now let us take first value i.e. 10. The node with value 10 will be the root node we will attach
this root node as left child of dummy node.
The NULL links of root's left and right child will be pointed to dummy.
Now next comes 8. The 8 will be compared with 10, as the value is less than 10, we will attach 8
as left child of 10 and we will set root's 1th field to 1, indicating that the node 10 is having left
child. See then how the links are arranged.
New → left = root → left
New → right = root;
root → left = New;
root → lth = = 1;
Note that the left link of node 8 points to its inorder predecessor and right link of node 8 points to
its inorder successor.
Next comes 6. The value 6 will be first compared with root i.e. with 10. As 6 is less than 10, we
will move on left subbranch. The 6 will then be compared with 8, so we have to move on left
subbranch of 8. But Ith of node 8 is 0, indicating that there is no left child to 8, so we will attach
6 as left child to 8.
Then comes 12. We will compare 12 with 10. As 12 is greater than 10, we will attach the node
12 as right child of 10.
Note that the left field of node 12 points to its inorder predecessor and right field of node 12
points to its inorder successor. Thus by attaching 9, 11, 14 as appropriate children, the threaded
binary tree will look like this
Such a threaded tree is called inorder threaded binary tree.
Ex. 4.10.1: Create threaded binary tree for 10, 20, 30, 40, 50.
Sol. :
Advantages of threaded binary trees
1. Due to NULL links in binary tree certain amount of memory gets wastage. This wastage of
memory is utilized by using threads.
2. The predecessor and successor of any node can be accessed effectively.
Disadvantage of threaded binary trees
1. Insertion and deletion of nodes become complex in threaded binary tree, since thread and
link manipulation is required on every insertion.
It is not possible to predict a binary search tree uniquely with one traversal. The one traversal
gives ambiguous result.
For example:
Consider the inorder traversal as ABC the trees could be as shown in Fig. 4.11.1.
Thus the only inorder traversal gives two different trees. So, to predict the exact tree from the
tree traversals we require atleast two traversals, say, inorder and postorder traversals.
Let us see the procedure of predicting a binary tree from given traversals.
Postorder :H I D E B F G C A
Inorder :H D I B E A F C G
Step 1:
The last node in postorder sequence is the root node. In above example "A" is the root node.
Now observe inorder sequence locate the "A". Left sequence of "A" indicates the left subtree and
right sequence of "A" indicates the right sub-tree.
i.e. as shown in Fig. 4.11.2.
Step 2:
Now, with these alphabets H, D, I, B, E observe the postorder and sequences.
Postorder H I D E B
Inorder H D I B E
Here B is parent node, therefore pictorically tree will be,
Step 3:
With the alphabets H, D and I observe both the sequences.
Postorder H I D
Inorder H D I
D is the parent node, H is leftmost node and I is the right child of D node. So tree will be as
shown in Fig. 4.11.4.
Step 4:
Now we will slove for right sub-tree of root "A". With the alphabets F, C, G observe both the
sequences.
Postorder F G C
Inorder F C G
'C' is the parent node, F is the left child and G is the right child. So finally the tree will be as
shown in Fig. 4.11.6.
AVL Trees
Adelsion Velski and Lendis in 1962 introduced binary tree structure that is balanced with respect
to height of subtrees. The tree can be made balanced and because of this retrieval of any node
can be done in O(logn) times, where n is total number of nodes. From the name of these
scientists the tree is called AVL tree.
• Definition
An empty tree is height balanced if T is a non empty binary tree with T L and TR as its left and
right subtrees. The T is height balanced if and only if,
i) TL and TR are height balanced.
ii) HL - hR <=1 where hL - hR are heights of TL and TR
The idea of balancing a tree is obtained by calculating the balance factor of a tree.
• Definition of Balance Factor
The balance factor BF(T) of a node in binary tree is defined to be h L - hR where he hL and hR are
heights of left and right subtrees of T.
For any node in AVL tree the balance factor i.e. BF(T) is -1, 0 or +1
• Height of AVL tree
Theorem: The height of AVL tree with n elements (nodes) is O(logN).
Proof: Let an AVL tree with N nodes in it. Nh be the minimum number of nodes in an AVL tree
of height h.
In worst case, one subtree may have height h-1 and other subtree may have height h−2. And both
these subtrees are AVL trees. Since for every node in AVL tree the height of left and right
subtrees differ by at most 1. Hence,
Nh = Nh_1+Nh_2+1
Where Nh denotes the minimum number of nodes in an AVL tree of height h.
N0=0 N1 =2
We can also write it as
N> Nh = Nh−2 + Nh_2+1
> 2Nh-2
> 4Nh-4
.
.
.
> 2i Nh-2i
If value of h is even, let i = h/2-1
Then equation becomes,
N > 2h/2-1 N2
= N > 2h/2-1x4 N2 =4
= O (log N)
If value of h is odd, let i= (h-1)/2 then equation becomes.
N > 2(h-1)/2Nı
= N > 2(h-1)/2x1 N1 =1
h=O(log N)
This proves that height of AVL tree is always O(log N). Hence search, insertion and deletion can
be carried out in logarithmic time.
Theorem : The height of AVL tree h with minimum number of nodes n is 1.44 log n.
Proof ; Let Fh be the AVL tree with height h having minimum number of nodes. The tree can be
shown as below.
Hence minimum number of nodes in AVL tree is = Length of left subtree + Length of right
subtree + 1
|Fh| = |Fh-1| + | Fh-2| + 1
Also
|F0|=1 and |F1| = 2
This denotes the Fibonacci tree.
Adding 1 to both sides.
|Fh|+1=(|Fh-1|+1)+(|Fh-2|+1).
Thus the numbers | Fh|+1 are Fibonacci numbers. Using approximate formula for Fibonacci
numbers, we will ge tan approximate value as :
|Fh|+1=1/√5 (1+√5/2) h+3
Taking logarithm
=h≈ 1.44 log | Fh |
Hence the worst case height of an AVL tree with n nodes is 1.44 log n.
The Fibonacci trees are as shown below.
Difference between AVL tree and binary search tree
Insert 25
We will attach 25 as a right child of 18. No balancing is required as entire tree preserves the
AVL property.
Insert 28
The node '28' is attached as a right child of 25. RR rotation is required to rebalance.
Now we will insert 12.
Step 1: Compare 13 with root node 10. As 13 > 10, search right subbranch.
Step 2: Compare 13 with 18. As 13 < 18, search left subbranch.
Step 3: Compare 13 with 12. As 13 > 12, search right subbranch.
Step 4: Compare 13 with 13. Declare now "node is found".
The searching operation takes O (log n) time.
The main objective here is to keep the tree balanced all the times. Such balancing causes the
depth of the tree to remain at its minimum and therefore overall costs of search is reduced.
Binary Heap
In this section we will learn "What is heap?" and "How to construct heap?"
Definition: Heap is a complete binary tree or a almost complete binary tree in which every
parent node be either greater or lesser than its child nodes.
Heap can be min heap or max heap.
Types of heap
i)Min heap ii) Max heap
A Max heap is a tree in which value of each node is greater than or equal to the value of its
children nodes.
For example
A Min heap is a tree in which value of each node is less than or equal to value of its children
nodes.
For example:
Parent being greater or lesser in heap is called parental property. Thus heap has two important
properties.
Heap:
• Height of the tree: The maximum level is the height of the tree. The height of the tree is also
called depth of the tree.
For example:
• Complete binary tree: The complete binary tree is a binary tree in which all the levels of the
tree are filled completely except the lowest level nodes which are filled from left if required.
For example:
•. Almost complete binary tree: The almost complete binary tree is a tree in which
i) Each node has a left child whenever it has a right child. That means there is always a left
child, but for a left child there may not be a right child.
ii) The leaf in a tree must be present at height h or h-1. That means all the leaves are on two
adjacent levels.
For example:
In Fig. 4.16.5 (a) the given binary tree is satisfying both the properties. That is all the leaves are
at either level 2 or level 1 and when right child is present left child is always present.
In Fig. 4.14.5 (b), the given binary tree is not satisfying the first property; that is the right child is
present for node 20 but it has no left child. Hence it is not almost complete binary tree.
In Fig. 4.14.5 (c), the given binary tree is not satisfying the second property; that is the leaves are
at level 3 and level 1 and not at adjacent levels. Hence it is not almost complete binary tree.