Unit 2 Tree
Unit 2 Tree
INTRODUCTION
So far we have discussed the sequential and linked representation of “linear” data structures.
Arrays, stacks, queues and linked lists, all are linear in nature and have several uses as seen
earlier. The elements are stored in these data structures in an ordered linear manner.
But there are many applications where we do not have a one to one relationship between
data elements. We have to represent a one-to-many relationship between elements. Some
applications also use hierarchical information. For example, if you want to store information
about five generations of your family ( family tree) or to store the directory structure in a
computer, a linear representation will not be useful. You will have to use a non-linear
representation. For example, to represent the following structure, a linear data structure like
array, linked list etc. would be of no use.
Computer
An important non-linear data structure is a Tree. In this chapter we shall be studying this
data structure and its applications in greater detail.
TREE TERMINOLOGY
Definition of a Tree
A tree is a finite set of nodes with one specially designated node called the root and the
remaining nodes are partitioned into n > = 0 disjoint sets T1 and Tn where each of those sets is a
tree. T1 to Tn are called the sub trees of the root.
Example
9-1
9 - 22
Trees
B C D
E F G
In this example, A,B,C,D,E,F,G and H form a set of nodes with A as the root. The remaining
nodes are partitioned into three sets (trees) with B,C and D as their respective roots.
Null Tree
A tree with no nodes is a Null Tree
Node
A node of a tree is an item of information along with the branches to other nodes. The tree
shown in Fig 2.1 has 8 nodes.
Leaf node
A leaf node is a terminal node of a tree. It does not have any nodes connected to it . All
other nodes are called non-leaf nodes, or internal nodes.
H,F,G and D are leaf nodes.
Degree of a node
The number of subtrees of a node is called its degree.
The degree of A is 3, B is 2 and D is 0. The degree of leaf nodes is zero.
Degree of the tree
The degree of a tree is the maximum degree of the nodes in the tree.
The degree of the shown tree is 3.
Parent node
A parent node is a node having other nodes connected to it. These nodes are called the
children of that node.
The root is the parent of all its subtrees. A,B, and C are parent nodes.
Siblings
Children of the same parent are called siblings.
Example: B,C and D are siblings. E and F are siblings.
Descendents
The descendents of a node are all those nodes which are reachable from that node.
Example: E, F and H are descendents of B.
Ancestors
9 - 22
Trees
The ancestors of a node are all the nodes along the path from the root to that node.
Example : B and A are ancestors of E.
Level of a node
This indicates the position of a node in the hierarchy. The level of any node = level of its
parent +1. The root is considered to be at level 1.
Example: B, C and D are at level 2. H is at level 4.
Height or Depth of a Tree
The maximum level of any node in the tree is the height or depth of the tree.
Example: The given tree has a height = 4. This equals the length of the longest path from
the root to any leaf.
Forest
A forest is a set of n >= 0 disjoint trees i.e. if we remove the root, we get a forest of trees.
Example
B C D
E F G
H
(i) (ii) (iii)
Forest
B C
F
D E
Binary Tree
A binary tree can thus be defined as a finite set of nodes, with one specially designated
node called the root, and the remaining nodes partitioned into 2 disjoint sets TL and TR . Each of
9 - 22
Trees
those sets is a binary tree. TL is called the left sub tree and TR is called the right sub trees of
the root.
B C
D E
F G
Strictly Binary Tree
B C
D E F G
Full Binary Tree of depth 3
Total number of nodes = i 1 2 i-1 = 2d - 1
Number of leaf nodes = 2d-1 since all leaf nodes are at level d.
Number of non-leaf nodes = 2d-1 – 1
B C
D E F G
H I J
Almost Complete Binary Tree
B B
C C
D D
L e ft s k e w e d B in a ry T re e R ig h t s k e w e d B in a ry T re e
Skewed Binary trees
20
9 40
5 15 35 60
80
Binary Search Tree
Expression Tree
A binary tree can be used to represent an expression containing operands and operators. If
all the operators are binary, then the expression tree will be a strictly binary tree.
In an expression tree, the root contains the operators to be applied to the result obtained by
evaluating the left and right subtrees.
The operands are in the leaf nodes while the operators are in the internal nodes.
The expression tree for the expression a * b + c is:
c
*
a b
Binary expression tree
Expression : (a+b) * (c + d- e)
*
+ -
a b + e
c d
Binary expression tree
Since there are several applications of binary trees, it would be convenient to use binary
trees. Any tree can be represented as a binary tree. The reason for converting a tree to a binary
9 - 22
Trees
tree is that in the case of a general tree, each node has different number of children. Thus, we
have to think of how to implement variable size nodes. Implementing of such nodes is very
difficult and hence, operations on such trees will be complicated.
A binary tree has fixed sized nodes and hence it can be easily implemented. In a general
tree, one node can be related to many nodes. Thus, this relationship has to be converted to a
binary tree relationship . This means that the relationship should be characterized by at most
two quantities.
One method is the leftmost-child-right-sibling relationship. Every node has at the most
one leftmost child and at most one next right sibling. The node structure will be :
Data
Left child Right Sibling
Diagram
In this tree, the root is A. So A will be the root of the binary tree.
The leftmost child of A is B. So B is the left child of A
The closest sibling of B is C. So C is the next right sibling of B.
Leftmost child of C is H. So H is to the left of C.
C has the next closest sibling D. So D is the next right sibling of C
C has one child. So H is the left child of C.
H has a no left child but have sibling I, add I as right child.
I has no children but J is its right sibling, add J as right child.
D has left child E, E has sibling F. Add F as right child of E.
G is left child of F.
diagram
9 - 22
Trees
B C D
K H I J E F
A G
K C
H D
I E
J F
9 - 22
Trees
1 Sequential Representation
Since a binary tree with total ‘d’ levels will have maximum of 2d–1 nodes, we can use an
array of size 2d–1 to represent the binary tree. In this method, we will number each node of the
tree starting from the root. Nodes on the same level will be numbered left to right. These
values will be stored in the array “levelwise” i.e. nodes of level 1 first followed by nodes of level
2 and so on.
Example
0
A
1 2
B C
3 4
D E F G
Complete Binary Tree
1 2
B C
3 4
D E F G
7 8 9 10
0 1 2 3 4
A B C D E F G H I J K
1 2
B C
3 4
D E
F G
0 1 2 3 4
A B C D E F G
Representation of Binary Tree
B H e re , n u m b e r o f le v e ls d = 4
4
A rra y s iz e = 2 - 1 = 15
C 0 1 2 3 4
A B C D
2 Linked Representation
The above method of representation is good only for complete or almost complete binary
trees. For the other problems of sequential representation mentioned above, the linked
representation will be very efficient.
This is a more flexible representation and uses dynamic memory allocation. Since each
node stores information and contains at the most two children, we can define a node structure
9 - 22
Trees
which will store information as well links to the two children – left and right. The tree will consist
of nodes linked to each other by left or right pointers.
The node structure for a binary tree will be as follows.
le ft d a ta rig h t
Example 1
T re e L in ke d R e p re s e n ta tio n
N U LL N U LL N U LL N U LL
Linked Representation
Example 2
A N U LL
B
N U LL
C
N U LL N U LL
Linked representation
class node
{
node *left;
int data;
node *right;
public:
node(int n) //constructor
{ data=n; left=right=NULL; }
9 - 22
Trees
friend class tree;
};
The binary tree will be a linked sequence of nodes. In the case of a linked list, we have to
store the address of the first node of the list in a pointer. In the case of a binary tree, we will
need one pointer called “root” to point to the root node of the tree.
The class definition for the binary tree will be as follows :
class tree
{
node *root;
public:
tree() //constructor
{ root=NULL; }
// operations
};
We will implement some of these operations in the following sections. The class definition for
the binary tree can be written as :
9 - 22
Trees
class tree
{
node *root;
void preorder(node *currentnode);//private member functions
void inorder(node *currentnode);
void postorder(node *currentnode);
public:
tree() //constructor
{ root=NULL; }
void create();
void preorder();
void inorder();
void postorder();
void insert(char c);
void delete(char c);
int totalnodes();
int leafnodes();
void mirror(tree &);
void copy(tree &);
};
Let us consider each of these in detail. For each of these methods, there are three distinct steps
to be performed. These are printing data of the node, visiting its left sub-tree and visiting its right
subtree. These three steps have to be followed for each of the sub-tree of the binary tree so that
there is uniformity in traversal.
i. Preorder (Data-Left-Right)
9 - 22
Trees
a. Visit the root.
b. Traverse the left subtree in Preorder.
c. Traverse the right sub tree in Preorder.
ii. Inorder (Left-Data-Right)
a. Traverse the left subtree in Inorder.
b. Visit the root.
c. Traverse the right subtree in Inorder.
iii. Post-order (Left-Right-Data).
a. Traverse the left subtree in Postorder.
b. Traverse the right subtree in Postorder.
c. Visit the root.
Example 1
A
P re o rd e r : A B D C
In o rd e r : DBAC
B C
P o s to rd e r : D B C A
D
Binary Tree
Example 2
A
P re o rd e r : A B D G C E H IF
C In o rd e r : D G B A H E IC F
B P o s to rd e r : G D B H IE F C A
D E F
G H I
Binary Tree
Example 3
A
B P re o rd e r : A B C E IF J D G H K L
In o rd e r : E IC F J B G D K H L A
P o s to rd e r : IE J F C G K L H D B A
C D
E F G H
I J K L
Binary Tree
9 - 22
Trees
A simple method to perform these traversals will be to write DLR / LDR / LRD above each
node and mark the step which has been performed.
void tree::preorder()
{
//Calls a private member function to traverse
preorder(root);
}
void tree::inorder()
{
//Calls a private member function to traverse
inorder(root);
}
To perform non recursive traversals, let us consider a simple method. Assume the binary
tree is as shown below :
Each node of the tree is “touched” three times by the loop (the touches are numbered in the
figure): once on the way down before the left subtree is reached, once after finishing the left
subtree but before starting the right subtree, and once on the way up, after finishing the right
subtree.
To generate a preorder traversal, follow the loop and visit each node the first time it is
touched (before visiting the left subtree).
To generate an inorder traversal, follow the loop and visit each node the second time it is
touched (in between visiting the two subtrees).
To generate a postorder traversal, follow the loop and visit each node the third time it is
touched (after visiting the right subtree).
Algorithm
1. S is an empty stack used to store pointers to node
2. temp is a pointer to node and is equal to root. i.e. temp = root.
3. As long as temp is not NULL,
Push temp in stack
Move temp to its left.
4. If stack is empty
Go to step 7.
5. Pop temp from stack
Display data of node temp
Move temp to its right
9 - 22
Trees
6. Repeat from Step 3.
7. Stop
Example: Let us consider a binary tree as shown below. The steps carried out for the non
recursive inorder traversal are shown in the table.
+
c
*
a b
The stack can be implemented sequentially using an array of structure. The stack definition
will be as follows.
class stack
{
int top;
node* item[MAX];
public:
stack()
{
top = -1;
}
void push(node *p)
{
item[++top]=p;
}
9 - 22
Trees
node *pop()
{
return item[top--];
}
int isfull()
{ return top==MAX; }
int isempty()
{ return top==-1; }
};
Function
void tree::nonrec_inorder()
{
node *temp=root;
stack s;
We have seen how to obtain the preorder, inorder and postorder traversal expressions from
a binary tree. In this section, we will see how to build a binary tree given the preorder/postorder
and inorder traversals.
From the preorder and inorder traversal, we can construct the binary tree. For this,
i) We have to scan the preorder from first to last.
ii) The first element in the preorder becomes the root of the tree. Mark this
element in the inorder expression.
iii) All the elements to the left of this element in inorder will be in the left subtree
and all elements to its right will be in the right subtree.
iv) Repeat steps ii) and iii) for the remaining elements from preorder, constructing
sub-trees for the root.
9 - 22
Trees
B C
D E
F G
In a similar manner, we can construct a binary tree from the postorder and inorder traversals.
For this, we will have to read the postorder expression from the last element to the first.
Function
void tree::create()
{
node * temp, *newnode;
char ans, c,choice;
do
{
cout << “Enter the element to be attached “;
c=getchar();
newnode = new node(c); //call constructor of node class
if(root==NULL)
root = newnode;
else
{
temp = root;
while(1)
{
cout <<“Left or right (l/r) of %d?” << temp->data;
cin>>ans;
if(ans == ‘l’)
if(temp->left == NULL)
9 - 22
Trees
{ temp->left = newnode; break; }
else
temp = temp->left;
else
if(temp->right == NULL)
{ temp->right = newnode; break; }
else
temp = temp->right;
}
}
cout<<“Any more nodes: ”;
cin>>choice ;
} while ( choice == ‘y’) ||(choice==’Y’);
}
OTHER OPERATIONS
1 Inserting an element in a binary tree
Once a binary tree has been created, we may want to add data elements later. Hence we
will have to insert the element in the binary tree at the appropriate position as specified by the
user. To insert an element, we will have to follow the same procedure that was followed for
adding nodes while creating the tree i.e. by asking the user whether the has to attached to the
left or right of an existing node in the tree starting from the root node.
Algorithm
1. Start
2. Accept data to be inserted.
3. Create a new node for the data
4. Temp = root.
5. If root = NULL then
Make new node as root. Go to step 9
6. Ask user whether to attach element to Left / Right of temp. Accept ans.
7. If ans = left
If temp does not have a left child
Attach node to left of temp. Go to step 9.
Else
Move temp to its left. Go to step 6
8. If ans = right
If temp does not have a right child
Attach node to its right of temp. Go to step 9.
Else
Move temp to right. Go to step 6
9 - 22
Trees
9. Stop.
The function to insert a node is given below. The function will accept the root of the tree and
the element to be inserted as parameters.
if(ans == ‘l’)
if(temp->left == NULL)
{ temp->left = newnode; break; }
else
temp = temp->left;
else
if(temp->right == NULL)
{ temp->right = newnode; break; }
else
temp = temp->right;
}
}
}
2 Copying a Tree
Copying a binary tree creates an exact image of the tree. This can be performed by a
recursive method.
We will start from root. (i.e. root of tree1). If the root is NULL, the copied tree is also NULL
and hence NULL is returned as the copied tree. If a tree exists, a new node is created and it
becomes the root of the new tree. If root1 has a left child, a left child is created for the new tree.
The same applies for the right child. The process is repeated for the left sub-tree and the right
sub-tree in the same manner as the original tree.
Function
void tree::copy(tree &t)
{
copy(root,t.root); //call a private member function
9 - 22
Trees
}
10 10
6 20 6
2 9 30 30 9 2
O rig in a l T re e M irro r
Figure 2. 1 Mirror of a Tree
In order to mirror a tree, the left and right children of each node have to be interchanged.
We will have to begin from the lowest level and move upwards till the children of the root are
interchanged.
void tree :: mirror(tree &t)
{
mirror(root,t.root);
}
int tree::countleafnodes ()
{
return countleafnodes(root);
}
if (root == NULL)
return countleaf;
if (root left == NULL && root right == NULL)
return ++ countleaf;
countleafnodes (root left);
countleafnodes (root right);
}
9 - 22
Trees
5 5 20
1
9 - 22
Trees
1 6 15
13
Thus, all the values in the left subtree are < root and those in the right subtree
are > root.
Note: The position of a node in the tree depends upon its time of insertion. For Example, if
the node 15 was inserted before 20, the tree would look like.
10
5 15
1 6 13 20
Binary Search Tree
1. Initially , root = NULL
2. Read a key value and store in node newnode
3. If root == NULL
assign newnode to root, go to step 6
4. temp = root
5.
if key < temp data
if temp does not have a left child
attach newnode to temp left, go to step 6
else
temp = temp left, go to step 5
else
9 - 22
Trees
if temp does not have a right child
attach newnode to temp right , go to step 6
else
temp = temp right, go to step 5
6. Repeat from 2 till all values have been put into the tree.
7. Stop
Function
For example, if tree is as follows and the value to be inserted is 4. To insert 4, compare it
with 8. 4 is < 8 and hence it should be to the left of 8. Further compare it with 5. 4 is less than 5.
So 4 should be to the left of 5. We will now compare 4 with 3. 4 is > 3 and 3 does not have a
right child. So attach 4 as right child of 3.
8
5 20
3 7 15 45
1 11
Algorithm
1. Start
2. Accept value to be inserted.
3. Create a new node for the value.
4. temp = root
5. if root = NULL then
Make new node as root. Go to Step 8.
6. if value < temp data
if temp does not have a left child
attach newnode to temp left, go to step 8
9 - 22
Trees
else
temp = temp left, go to step 6
7. if value >= temp data
if temp does not have a right child
attach newnode to temp right , go to step 8
else
temp = temp right, go to step 6
8. Stop.
Function
5 20
3 7 15 45
1 11
node *bst::search(int value)
{
if(root != NULL)
{
if ( root->data == value ) /* match found */
return root;
10 12 15
6 6 10 12
7 13 7 13
Deleting a leaf node
3 11 d e le te 3 11
5
1 5 9 14 1 6 9 14
d
6 10 12 15 7 10 12 15
7 13 13
Deleting a node having one child
8 8
3 11 3 12
d e le te
14 11
1 5 9 1 5 9 14
6 10 12 15 10 13 15
6
13
7 7
Deleting a node having two children
In the following algorithm, we will be using pointer r to point to the node that will replace the
node to be deleted.
Algorithm
1. Start
2. Accept n i.e. number to be deleted
3. Search n in the tree
4. If n is not found
go to step 10
5. temp points to the node containing n.
6. parent is a pointer to temp’s parent.
7. if temp left = = NULL
r = temp right
else
if temp right = = NULL
r = temp left
else /* Node has both children */
father = temp
r = temp right
son = r left
while son ! = NULL
father = r ; r = son ; son = r left
if father ! = temp
father left = r right ; r right = temp right
r left = temp left
8. If parent == NULL
root = r
else
if temp == parent left
parent left = r
else
parent right = r
9. free temp
9 - 22
Trees
10. stop
if(parent==NULL)
root=r;
else
if (temp == parent -> left)
parent -> left = r;
else
parent-> right = r;
delete temp;
return ;
}
5 20
3 7 15 45
1 11
Binary Search Tree
will be
8
5 20
3 7 15 45
1 11
i.e. we first display the root, its children, then their children and so on.
Algorithm
1. Start
2. temp = root, dummy = NULL
3. Add temp to Queue.
4. Add dummy to Queue
5. remove temp from queue
6. if temp == NULL
if (queue is not empty)
goto the next line
add dummy to queue
7. if temp != NULL
9 - 22
Trees
display data of temp
if temp has left child
add left child to the queue
if temp has a right child
add right child to the queue
8. Repeat from 5 till Queue becomes empty.
9. Stop
For the levelwise display, the queue will have to store node addresses of the tree. Hence,
the structure of the queue will be
class queue
{
int front, rear;
node * item [MAX];
};
Function
void bst::levelwise ()
{
1 7 10 30
1 7 30
9 - 22
Trees
Binary Search Tree
Inorder traversal – 1 5 7 8 10 20
The inorder threaded tree will be
8
5 10
1 7 20
Inorder-threaded tree
1 7 20
3. Postorder threading
A null left and right link is replaced by a pointer to the node which is its predecessor and
successor respectively in postorder.
Example
Postorder 1 7 5 20 10 8
8
5 10
1 7 20
8
5 10
1 7 20
Node Structure
Since the NULL links are to be replaced by threads , we need to have some way of
differentiating between a thread and a child. This can be done by having two integer fields
lthread and rthread. If lthread has a value 1, it will indicate that the left link is a thread. The
same applies for the lthread.
class tnode
{
int data;
tnode *left, *right;
int lthread, rthread;
};
For the threaded binary tree, we will have to use an extra node called the head which is an
empty node. The class definitions will be as follows :
9 - 22
Trees
class tnode
{
int data;
tnode *left, *right;
int lchild, rchild;
public:
tnode(int n=0)
{
data=n;
left=right=NULL;
lchild=rchild=0;
}
friend class threaded;
};
class threaded
{
tnode *head;
tnode *root;
public:
threaded()
{
head = new tnode();
root=NULL;
}
// operations
};
head
1. 10
10
head
2. 5
10
head
3. 15 10
5 15
head
10
4. 8
5 15
head
10
5. 30
5 15
8 30
Function
9 - 22
Trees
void threaded::create_threaded()
{
tnode *temp, *newnode;
char ans;
do
{
cout<<“Enter the data :”;
cin>>n
newnode= new node(n); //constructor
if(root==NULL)
{
root=newnode;
newnode->left=newnode->right=head;
9 - 22
Trees
}
else
{
temp=newnode;
while(1)
{
if(n<temp->data)
if(temp->lchild==0)
{
newnode->left=temp->left;
temp->left=newnode;
temp->lchild=1;
break;
}
else
temp=temp->left;
else
if(temp->rchild==0)
{
newnode->right=temp->right;
temp->right=newnode;
temp->rchild=1;
break;
}
else
temp=temp->right;
}
}
cout<<“Any more nodes :”;
cin>>ans;
}while(ans == ‘y’);
}
Algorithm
1. Start
2. Set temp = leftmost of root using the code
while ( temp->left != NULL)
temp = temp->left
9 - 22
Trees
3. Display data of temp
4. if temp has a right child, set temp to leftmost of right child:
temp = temp->right
while ( temp->left !=NULL)
temp=temp->left
else
temp = temp right i.e use thread
5. Repeat from 3 as long as temp ! = head.
6. Stop.
For example, consider the following right in-threaded binary tree. Applying the above
algorithm, we start from the root i.e. from 8. temp is positioned to node 1 ( Step 2). Since
temp does not have a right child, we use the thread and move temp to 5 ( Step 4). 5 has a
right child so temp is moved to 7. 7 does not have a right child so using the thread, temp is
moved to 8. 8 has a right child so temp is moved to the leftmost of the right child i.e. it
remains at 10. From 10, temp moves to node 20 ( leftmost of right child) and since 20 does
not have a right child, temp goes to the header node using the thread and the process stops.
8
5 10
1 7 20
Function
void threaded::inorder()
{
tnode *temp = root;
do
{
while(temp->lchild == 1 ) /* move to leftmost node */
temp = temp->left;
cout<<temp->data;
Algorithm
1. Start
2. temp = root.
3. Display data of temp.
4. if temp has a left child
Move temp to left
Else
IF temp has a right child
Move temp to the right
Else
While ( temp does not have a right child )
Move temp to right
Move temp to the right
5. Repeat from 3 as long as temp does not reach header.
6. Stop.
Example: Let us consider the tree in the Fig.**** for preorder traversal. We start with the root
i.e. temp is at 8. Display 8. Since temp has a left child, we move temp to node 5. Display 5.
Temp has a left child so move temp to node 1. Display 1. Temp does not have a left child. Temp
has a right child. So we move temp to 7. Display 7. Temp does not have a left child and right
child so we use the thread to move temp to 8. Temp has a right child so we move temp to the
right child i.e 10 and the same process is repeated for the sub-tree with root 10.
void threaded::preorder()
{
while(1)
{
cout<<root->data;
while(root->lchild==1)
{
root=root->left;
cout<<root->data;
}
if(root->rchild==0)
root=root->right;
else
{
while(root->rchild==1)
{
9 - 22
Trees
if(root->right==head)
return;
root=root->right;
}
if(root->rchild==1)
root=root->right;
}
}
}
8
5 10
1 7 20
For the postorder traversal, we need a check variable to determine the next action i.e. what
has to be done. The check variable is used the control the traversal depending upon the next
action which can be - left traversal, right traversal, visit node.
Algorithm
1.Start
2. NextAction = GoLeft
3. Loop while all nodes have not been visited
Case NextAction
GoLeft :
Traverse left subtree if it exists
Return to node
NextAction = GoRight
GoRight :
Traverse right subtree if it exists
Return to node
NextAction = VisitNode
VisitNode :
Visit Node
Find Parent of Node
//Set NextAction as given by parent
If Node is left child of parent then NextAction=GoRight
9 - 22
Trees
If Node is right child of parent then NextAction=VisitNode
If parent is the root then
Go to Step 4.
End case
End loop
4 Stop.
In order to perform the above traversal, the problem is : How can we locate the parent of a
node without using recursion or stack?
This can be done as follows :
During the traversal of a subtree the value of NextAction is continually changed as each
node of the subtree is processed. Hence need some way of determining the previous value of
NextAction on the return to the original node.
APPLICATIONS OF TREES
The tree data structure has a large number of applications. Some of these are discussed
below.
1. Set Representation : Trees can be used to represent disjoint sets and perform
operations like union and find on the set efficiently.
2. Game Trees: Trees are widely used in playing games using computers. Games such
as tic-tac-toe, chess etc use trees. A tree is used to identify current status and plan
strategies so as to make the “best” move.
3. Decision Making : A binary tree is very useful when two-way decisions have to be
made.
4. Searching : Search trees are very widely used to store record keys and search them in
an efficient manner.
5. Data Encoding : Binary trees are used to encode large volumes of data using the
Huffman Coding algorithm.
6. Sorting: A sorting method called “Heap Sort” is based on the binary tree structure.
9 - 22
Trees
1 Game Trees
One very interesting application of trees is in playing board games like tic-tac-toe, chess,
Chinese checkers etc. The main reason to use trees is to determine what would be the best
move to be made at a certain situation in a game.
Starting at any position, it is possible to construct a tree of the possible board positions which
will result after a specific move. Such a tree is called a game tree.
Starting State
M1 M2
Mn
Here, M1, M2 etc are the moves made and RS1…RSn are the resulting states.
For example, let us consider the very popular 2-player game of Tic-Tac-Toe. In this board
game, there are 3X3 squares in which each player places his symbol which is either an X or O.
The aim is to get the same symbol in either one row, column or diagonal. The player to
accomplish this first, wins.
To find out which is the best move to be made, an evaluation function is defined which
accepts a board position and the position of X or O and returns a number telling “how good” the
move would be. The higher this number, the better is the move. It would be possible to calculate
the best move if the function can “look ahead”. This means that if the function can generate all
possible positions starting from a specific point, then it would be possible to select the best
move.
Advantages of Game trees
Game trees are very useful in determining the next move a player should make. For small
games like tic-tac-toe, the resulting game trees are very small and can be easily generated.
However, for games like chess, it is estimated that the game tree has more than 10100 nodes and
will take more than 1080 years to generate!. Thus, it is not possible to generate the entire game
tree and then take the decision about the move. In such cases, the decision is made by looking
ahead only a few levels.
A>B
Yes No
A>C B>C
Yes Yes No
No
The leaf nodes represent the solutions.
A C B C
A very popular example is the 8 coins problem in which there are 8 coins. 7 coins are of
equal weights but one coin has a different weight. We want to find out which is that coin and
also whether it is heavier or lighter than the rest. The only equipment that we have is a two arm
weighing balance. In addition, the number of comparisons should be minimum. The following
tree shows all the possible sequences.
Diagram
In the above example, let us assume that the sum of a+b+c is equal to d+e+f. This means
that the false coin is either g or h. We can then compare g and h with one other correct coin to
find out the false coin.
To write a program for the above, we have to write a sequence of if-else statements or a
switch case to mirror the above tree.
SOLVED PROBLEMS
1. Prove by induction that
9 - 22
Trees
= i 1 total number of nodes on level i
k
= i 1 2 i-1
= 2k - 1
2. Construct a binary expression tree from the prefix and infix expression.
Prefix : *+ab-+cde Infix : a+b * c+d-e
Soln: From the two expressions, we can construct the binary expression tree. The first
character in prefix is *. Hence, the root of the tree is *. The left subtree will have (A+B) and the
right sub-tree will be the expression (C+D-E) as seen from the infix expression. The steps are
shown below.
*
+ -
a b + e
c d
5 20
3 7 15 25
1
4. Write an algorithm to determine is a binary tree is strictly binary.
Soln: In a strictly binary tree , every non leaf node has two children. This means that a node in
the tree must either be a leaf node or it must have two children. If any node does not satisfy
these criteria, then the tree is not a strictly binary tree. To visit every node, we can use any
traversal method. Starting from the root, we can check if the node satisfies the criteria. If yes,
we can continue to check the left sub-tree. If it is also strictly binary, then we can check the sub-
tree.
6. What is the difference in the search operation carried out on a binary tree and a binary
search tree?
Soln: In the case of a binary tree, to search for an element, the entire tree has to be searched.
Any traversal method can be used to visit each node of the tree. If there are n nodes, the time
complexity of search is O(n).
In a BST, the nodes are organized according to their values. Thus, the whole tree does not
have to be searched. Comparing the key value with the node value, search will proceed either in
the left sub-tree or right-subtree. Hence, after every comparison, one part of the tree is
eliminated. The complexity is O(log2 n) which is much faster than O(n).
7. Write a function which returns the parent of a given node in a Binary Search Tree.
Soln : To find the parent of a given node, we have to search the node in the BST by comparing
the value in the node with the node values in the tree. Since it is a BST, the nodes will be
arranged according to their values such that the left node will have a value < parent and the
right child will have a value > parent.