Anda di halaman 1dari 60

TREES

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

Hardware

Motherboard

Firmware

Peripherals

Software

System

Application

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.

9-1

9-2
Trees

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 T 1 and Tn where each of those sets
is a tree. T1 to Tn are called the sub trees of the root.
Example

A
C

B
E

a) Generic Tree b) Example Tree

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.

9-3
Trees

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

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
E

H
( i)

G
( ii)

( iii)

9-4
Trees
Forest

If the root A is removed, we get a forest of three trees.


Binary Trees

A binary tree is a finite set of nodes, which is empty or partitioned into three sets; one
which is the root and the other two are binary trees called its left and right subtrees.
It is a tree where every node can have at the most two branches (children)

A
C

B
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 T L and TR .
Each of those sets is a binary tree. TL is called the left sub tree and TR is called the right
sub trees of the root.
Strictly Binary Tree

A strictly binary tree is a binary tree where all non-leaf nodes have two branches.

A
C

B
D

E
F

Strictly Binary Tree

Full Binary Tree

A full binary tree of depth k is a binary tree of depth k having 2 k-1 nodes i.e. it has the
maximum number of nodes a binary tree of depth k can have.

A
C

B
D

9-5
Trees
Full Binary Tree of depth 3

Complete Binary Tree

A full binary tree can be represented sequentially by numbering the nodes from 1 to n
starting from the nodes on level 1, then level 2 and so on. Nodes on a level are numbered
left to right.
A binary tree with n nodes and of depth k is complete iff its nodes correspond to the
nodes which are numbered from 1 to n in the full binary tree of depth k.
Maximum Nodes in a binary tree

The maximum number of nodes on level i is 2 i-1. (For example, on level 1, there is only
one node the root ). A complete binary tree with a total of d levels (from 1 to d) contains
d

Total number of nodes =

2 i-1 = 2d - 1

i 1

Number of leaf nodes = 2

d-1

since all leaf nodes are at level d.

Number of non-leaf nodes = 2d-1 1


Almost complete binary tree

A binary tree with d levels is almost complete if levels 1 to d-1 are full and the last level
i.e. level d is partially filled from left to right.

A
C

B
D
H

E
I

Almost Complete Binary Tree

Skewed Binary Tree

The branches of this tree have either only left branches or only right branches.
Accordingly the tree is called left skewed or right skewed tree.

9-6
Trees

D
L e f t s k e w e d B in a r y T r e e

R ig h t s k e w e d B in a r y T r e e
Skewed Binary trees

Binary Search Tree

A binary search tree is a binary tree in which the nodes are arranged according to their
values. The left node has a value less that its parent and the right node has a value greater
than the parent node, i.e all nodes in the left subtree have values less than the root and
those in the right subtree have values greater than the root.

20
40

9
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

9-7
Trees
Binary expression tree

Expression : (a+b) * (c + d- e)

*
-

+
b

Binary expression tree

CONVERTING TREE TO A BINARY 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 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

Let us understand this with an example. Consider the tree as shown.

Diagram

In this tree, the root is A. So A will be the root of the binary tree.

9-8
Trees

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 B is E. So E is to the left of B.

E has one sibling F. So F is the next right sibling of E.

C has one child. So G is the left child of C.

C has the next closest sibling D. So D is the next right sibling of C

H is the leftmost child of D. So H is the left child of D.

H has a right sibling I.

I has no children but J is its right sibling.

The final binary tree will be as follows :

diagram
A

9-9
Trees

BINARY TREE REPRESENTATION


As seen for most of the data structures earlier, a binary tree can be represented in two
ways.
1.

Sequential Representation

2.

Linked Representation.

Sequential Representation
d

Since a binary tree with total d levels will have maximum of 2 1 nodes, we can use an
d

array of size 2 1 to represent the binary tree. In this method, we will number each node of

9 - 10
Trees

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

A
1

B
D

Complete Binary Tree

Here, the number of levels is 3. We need an array of size 23-1 = 7 elements.


The tree representation will be:
0

A
B
3

D
8

C
4

2
G

10

Almost Complete Binary Tree

This representation allows random access to any node as shown


i.

The ith node is at location i where


(0 < i < n)

ii.

The parent of node i is at location (i-1)/2 ( i=0 is the root and has no parent)
Example
Parent of J (node 9) = (91) /2
= 8/2 = 4

9 - 11
Trees

i.e. E.
iii.

Left child of a node i is present at position 2i + 1 if 2i + 1< n


If 2i +1 > = n , the node i does not have a left child.
Example
Left child of B (node 1) = 2 1 + 1
= 3
= D
Left child of F ( Node 5) = 2 5 + 1
= 10 + 1
= 11
= n
Thus, F does not have a left child.

iv.

Right child of a node i is present at position 2i + 2 if 2i + 2 < n. If 2i + 2 > = n


then node at position i does not have a right child.
Example
Right child of B (node 1) = 2 1 + 2 = 2 + 2 = 4
Since 4<7, the node E is the right child.
Right child of G (node 6)

= 2 6 + 2 = 14 > n

Thus G does not have a right child.


Note: The above formulae will work only for almost complete binary trees. If the
tree is not a complete or almost complete binary tree, it can be converted to almost
complete binary tree by showing dummy nodes as shown.
0
A

B
D

E
F

9 - 12
Trees
Representation of Binary Tree

Disadvantages of Sequential representation


1. Since we are using arrays, there is a limitation on its size i.e. we cannot store
information of more nodes than the specified array size.
2. If the tree is not an almost complete binary tree, many array positions will be
unutilized.
Example Consider the skewed tree and its representation
A
B
C

H e r e , n u m b e r o f le v e ls d = 4
4
A r r a y s iz e = 2 - 1
= 15
2
3
4
D

Representation of skewed tree

Thus, only 4 positions are occupied and 11 are wasted.


3. Nodes cannot be inserted or deleted. It will involve a lot of movement of nodes and
will be very complicated. Hence, the linked representation is preferred.

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 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 f t

d a ta

r ig h t

Binary Tree node

9 - 13
Trees

The linked representations of some binary trees are shown below.


Example 1

L in k e d R e p r e s e n t a tio n

T re e

N U LL

N U LL

N U LL

N U LL

Linked Representation

Example 2

NULL

N U LL

C
NULL

N U LL

Linked representation

Class definitions for Binary Tree


This node structure for the binary tree can be defined as follows:
classnode
{
node*left;
intdata;
node*right;
public:
node(intn)//constructor
{data=n;left=right=NULL;}
friendclasstree;
};
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.

9 - 14
Trees

The class definition for the binary tree will be as follows :


classtree
{
node*root;
public:
tree()//constructor
{root=NULL;}
//operations
};

PRIMITIVE OPERATIONS ON BINARY TREES


There are a variety of operations that can be carried out on binary trees. We will
implement a minimal set of operations. The other operations can be performed on the basis
of these basic operations. These are :
1. Creating a binary tree
2. Traversal of a binary tree (Preorder, Inorder and Postorder)
3. Inserting an element
4. Deleting an element
5. Searching for an element
6. Traversing a binary tree
7.

Checking whether a binary tree is empty

8. Checking whether two binary trees are equal


9. Copying one binary tree to another
10. Counting total number of nodes
11. Counting leaf nodes
12. Copying a binary tree
13. Mirror of binary tree
We will implement some of these operations in the following sections. The class definition
for the binary tree can be written as :

9 - 15
Trees

classtree
{
node*root;
voidpreorder(node*currentnode);//privatememberfunctions
voidinorder(node*currentnode);
voidpostorder(node*currentnode);
public:
tree()//constructor
{root=NULL;}
voidcreate();
voidpreorder();
voidinorder();
voidpostorder();
voidinsert(charc);
voiddelete(charc);
inttotalnodes();
intleafnodes();
voidmirror(tree&);
voidcopy(tree&);
};

BINARY TREE TRAVERSALS


In the case of linear data structures, we can display complete information about all
elements very easily because they are all stored in a linear manner. Now consider that you
have to display the information stored in a binary tree. How would you go about it? You
would start from the root. But after that, there are two paths left and right. Whichever
path you take, you have to return to the path that was left out. At every node, you will have
to decide whether to go left or right and then when the path ends, you have to visit the
path that you did not take earlier. This will be extremely difficult unless you go about it in a
structured, systematic order.
For this purpose, there are traversal methods, which allow each and every node to be
visited exactly once. Traversing a tree means visiting all its nodes to get the complete tree
information. Three methods of tree traversals have been developed.
i.

Preorder ( or Depth-First Order)

ii.

Inorder ( or Symmetric Order )

iii.

Postorder

9 - 16
Trees

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)

a. Visit the root.


b. Traverse the left subtree in Preorder.
c.
ii.

Traverse the right sub tree in Preorder.

Inorder (Left-Data-Right)
a. Traverse the left subtree in Inorder.
b. Visit the root.
c.

iii.

Traverse the right subtree in Inorder.

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

P re o rd e r : A B D C
In o rd e r
: DBAC
P o s to rd e r : D B C A

B
D

Binary Tree

Example 2

A
C

B
E

D
G

P re o rd e r : A B D G C E H IF
In o rd e r
: D G B A H E IC F
P o s to rd e r : G D B H IE F C A

F
I
Binary Tree

Example 3

9 - 17
Trees

A
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

B
C

D
F

E
I

G
J

H
K

L
Binary Tree

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.

Recursive Functions for Traversals

If we study the methods above, it is obvious that the definition itself is recursive in
nature. These three methods can be easily accomplished using recursive functions. To
perform the traversals, all we need to know is the node address of the root of the tree.
Hence, the root, which is a pointer to a NODE, is passed to the function.
1.

Recursive Preorder Traversal

voidtree::preorder()
{
//Callsaprivatememberfunctiontotraverse
preorder(root);
}
voidtree::preorder(node*currentnode)
{
if(currentnode!=NULL)
{
cout<<currentnodedata;
/*D*/
preorder(currentnodeleft);
/*L*/
preorder(currentnoderight);
/*R*/
}
}
2.

Recursive Inorder Traversal

voidtree::inorder()

9 - 18
Trees

{
//Callsaprivatememberfunctiontotraverse
inorder(root);
}
voidtree::inorder(node*currentnode)
{
if(currentnode!=NULL)
{
inorder(currentnodeleft);
cout<<currentnodedata;
inorder(currentnoderight);
}
}
3.

/*L*/
/*D */
/*R*/

Recursive Postorder Traversal

voidtree::postorder()
{
//Callsaprivatememberfunctiontotraverse
postorder(root);
}
voidtree::postorder(node*currentnode)
{
if(currentnode!=NULL)
{
postorder(currentnodeleft);
/*L*/
postorder(currentnoderight);
/*R*/
cout<<currentnodedata;
/*D */
}
}

Non recursive Traversals

The traversals seen above are done using recursive functions. However, recursive
functions have the following disadvantages:
1.

Recursive functions have added overheads because when a function is called and
returned, an internal stack is used.

2.

Execution is slower because control has to be transferred to the function and back.

3.

There is a possibility of the overflow of the internal stack.

9 - 19
Trees

To perform non recursive traversals, let us consider a simple method. Assume the binary
tree is as shown below :

We have drawn a loop around the tree as shown.

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).

9 - 20
Trees

Non Recursive Inorder Traversal


To avoid the above problems, we can write a non-recursive traversal. We shall write a
non recursive inorder traversal. For this purpose, we will have to use a stack since, for the
inorder traversal (LDR), we have to traverse from the child to the parent. However, there is
no pointer in the child node which can take us to the parent. So we have to use a stack so
that as we move leftwards, we can push all those addresses in the stack so that we can go
back to those nodes later.
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

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
Temp
points to

Step
Number

b
Stack ( contains
node address of )
+

Output

9 - 21
Trees

+, *

+, * , a

+, *

a*

+b

a*

a*b

Empty

a*b+

a*b+

Empty

a*b+c

Empty

a*b+c

NULL

The stack can be implemented sequentially using an array of structure.


definition will be as follows.
classstack
{
inttop;
node*item[MAX];
public:
stack()
{
top=1;
}
voidpush(node*p)
{
item[++top]=p;
}
node*pop()
{
returnitem[top];
}
intisfull()
{returntop==MAX;}
intisempty()
{returntop==1;}
};

The stack

9 - 22
Trees
Function

voidtree::nonrec_inorder()
{
node*temp=root;
stacks;
cout<<Thenonrecursiveinordertraversalis:<<endl;
while(1)
{
while(temp!=NULL)
{
s.push(temp);
temp=temp>left;
}
if(s.isempty)
break;
temp=s.pop();
cout<<temp>data;
temp=temp>right;
}
}

Constructing Binary tree from traversal expressions


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.

Example:

Preorder = ABDEFGC
Inorder = DBFEGAC

9 - 23
Trees

Here, A will be the root. From the inorder, the elements left to A are D, B, E, F, E and
G. These will be in the left subtree and C will be in the right subtree of A.
B is next in preorder. Since it is As left subtree, attach it to the left of A.
D is the next in preorder. Since it is also in As subtree, we have to check its position
with respect to B. It is in Bs left sub-tree in inorder. Attach it to left of B.
E is next in preorder. E is in As left subtree, it is to the right of B. Attach it to the right
of B.
F is in As left subtree. It is to the right of B. It is to the left of E. Attach it to left of E.
G is in As left subtree. It is to the right of B. Further, it is to the right of E. Attach it to
the right of E.
Finally C is in As right sub-tree. Attach it as the right child. The final tree is as shown.

A
C

B
D

E
F

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.

CREATING A BINARY TREE


We will be using the dynamic method to create a binary tree i.e. using the linked
implementation. To create the binary tree, The first element will be the root of the tree. We
will have to create the nodes for the remaining data elements one-by-one and then attach
the node to the tree at the appropriate position ( i.e. left or right ). The tree can be created
in two ways:
i)

We can go on attaching the nodes level-wise starting from the root. Since any
level will have maximum 2i-1 nodes, we can attach the nodes accordingly.
However, for this, we will have to remember the position where the node has to
be attached and also do a lot of traversal from the left subtree to right to attach
the nodes. Hence this method is more complicated.

9 - 24
Trees

ii)

Ask the user whether the node should be attached to the left or right. Continue
asking till we reach a position where the node can be attached to the tree.

The algorithm can be written as follows:


Algorithm

1. Start
2. root is initially NULL.
3. Accept data
4. Create a new node
5. Put data in node
6. if tree is empty i.e. root is NULL then
Make node as the root. Go to step 10.
7. Temp = root
8. Ask user whether to attach to Left / Right of temp. Accept ans.
9. If ans = left
If temp does not have a left child
Attach node to left of temp. Go to step 10.
Else
Move temp to its left. Go to step 8
14. If ans = right
If temp does not have a right child
Attach node to its right of temp. Go to step 10.
Else
Move temp to right. Go to step 8
15. Ask user Any more nodes?. Accept answer.
16. If answer = Yes, Go to step 3.
17. Stop.
Function

voidtree::create()
{
node*temp,*newnode;
charans,c,choice;

9 - 25
Trees

do
{
cout<<Entertheelementtobeattached;
c=getchar();
newnode=newnode(c);//callconstructorofnodeclass
if(root==NULL)
root=newnode;
else
{
temp=root;
while(1)
{
cout<<Leftorright(l/r)of%d?<<temp>data;
cin>>ans;
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;
}
}
cout<<Anymorenodes:;
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.

9 - 26
Trees
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. 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.
voidtree::insert(charch)
{
node*temp;
node*newnode=newnode(c);
if(root==NULL)
root=newnode;
else
{
temp=root;
while(1)
{
cout<<Leftorright(l/r)of%d?<<temp>data;

9 - 27
Trees

cin>>ans;
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;
}
}
}

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

voidtree::copy(tree&t)
{
copy(root,t.root);//callaprivatememberfunction
}
node*tree::copy(node*root1,node*root2)
{
//createatreewithroot2thesameastreewithroot1
if(root1!=NULL)
{
root2=newnode(root1>data);
root2left=copy(root1left);
root2right=copy(root1right);
returnroot2;
}
else

9 - 28
Trees

returnNULL;
}

Mirroring a Binary Tree


The mirror image of a tree contains its left and right sub-trees interchanged as shown

10

10
20

6
2

30

30

O r ig in a l T r e e

M ir r o r
Figure 2. 9 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.
This can be done by the following recursive function.
voidtree::mirror(tree&t)
{
mirror(root,t.root);
}
node*tree::mirror(node*root1,node*root2)
{
node*root2=NULL;
if(root1!=NULL)
{
root2=newnode(root1>data);
root2left=mirror(root1right);
root2right=mirror(root1left);
}
returnroot2;
}
The mirrored tree can be displayed by using any tree traversal method.

9 - 29
Trees

Counting the total nodes in a tree

In order to count the total number of nodes in a tree, we have to traverse the tree such
that each node is visited. Any one of the traversal methods can be used for this purpose.
The function can be written recursively as shown.
inttree::countnodes()
{
returncountnodes(root);
}
inttree::countnodes(node*root)
{
staticintcount=0;
if(root!=NULL)
{
count++;
countnodes(rootleft);
countnodes(rootright)
}
returncount;
}

Counting the leaf nodes of a tree

A leaf node is node, which has no children. Using any traversal method, the function to
count the leaf nodes can also be written recursively as before.
inttree::countleafnodes()
{
returncountleafnodes(root);
}
inttree::countleafnodes(node*root)
{
staticintcountleaf=0;
if(root==NULL)
returncountleaf;
if(rootleft==NULL&&rootright==NULL)
return++countleaf;
countleafnodes(rootleft);
countleafnodes(rootright);
}

9 - 30
Trees

BINARY SEARCH TREES


A binary search tree is a binary tree which is either empty or contains nodes which
satisfy the following.
i.

All keys in the left subtree < root.

ii.

All keys in the right subtree > root.

iii.

The right and left subtrees are also binary search trees.

1 Creation of Binary Search Tree


The creation of a Binary Search Tree (henceforth referred to as BST ) is slightly different
from a binary tree because, in a binary search tree, the elements are organized in a specific
manner. The nodes cannot be attached anywhere we want to, but they have to be attached
according to their value.
Let us understand the creation process by taking an example. If the data elements to be
put into the BST are: 10
20
15
5
1
7
13, the steps of creation as shown
below. The first element i.e. 10 will be the root of the tree and the remaining elements will
be attached by comparing their value with the root value. If their value is < 10, they will be
in the left sub-tree and if their value is > 10, they will be in the right sub-tree.
Example : The steps in creation of Binary Search tree for the data
10

20
10

15

ro o t
10

13
10 will be the root
20 > 10. Hence it is the
right child

10
20

20
10
15

20

15 > 10. But 10 already


has a right child. So
compare 15 with 20.
15 < 20.Hence 15 is the
left child of 20.

9 - 31
Trees

5<10. Thus, 5 is the left


child of 10

10
20

1 < 10. But 10 already


has a left child. So
compare 1 with 5.

10
20

1 < 5.Hence 1 is the left


child of 5.

6 < 10. Thus left subtree.

10
20

6>5. Thus 6 is the right


child of 5.

15

13 > 10. Right sub-tree

10

13

13 < 20. Left sub-tree

20

5
6

13<15. Left child.

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
15

5
1

13

20

Binary Search Tree

The algorithm to create a binary search tree is

9 - 32
Trees

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
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

voidbst::create()
{
NODE*newnode,*temp;
intn;
charans;
do{
newnode=getnode();
cout<<Entertheelementtobeinserted:;
cin>>n;
newnodedata=n;
newnodeleft=newnoderight=NULL;
/* attachnewnodetothetree*/
if(root==NULL)
root=newnode;
else
{
temp=root;

9 - 33
Trees

while(1)
{
if(n<tempdata)
if(templeft==NULL)/*tempdoesnothaveleftchild*/
{ templeft=newnode;break;}
else
temp=templeft; /* Movetempleft*/
else
if(tempright)==NULL)
{ tempright=newnode; break; }
else
temp=tempright;
} /* endwhile*/
cout<<\nAnymorenumbers?:;
cin>>ans;
} while(ans==y)||(ans==Y);
}

2 Insertion in a Binary Search Tree


When an element has to be inserted in a binary search tree, its position in the tree will
depend on its value. Thus, if its value is < root, it will be in the left side and if its value is >
root, it will be in the right sub-tree. Further, if the root already has a left child, then we
have to compare its value with the left child. The process continues till we find a node which
has a NULL link where it can be attached.
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
20

5
3
1
Algorithm

1. Start

15
11

45

9 - 34
Trees

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

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

Voidbst::insert(intn)
{
node*temp,*newnode;
newnode=newnode(n);
if(root==NULL)
root=newnode;
else
{
temp=root;
while(1)
{
if(n<tempdata)
if(templeft==NULL)
{ templeft=newnode;break;}
else
temp=templeft;
else
if(tempright)==NULL)
{ tempright=newnode; break; }
else

9 - 35
Trees

temp=tempright;
} /* endwhile*/
}
}

3 Searching an element in Binary Search Tree


Unlike searching in an ordinary binary tree, to search for a specific data element, we
dont have to traverse the entire tree. In a binary search tree, the data elements are
organized in a specific manner. So we can either search in the left sub-tree of the right subtree on the basis of the value to be searched. Thus, for every comparison made, we will have
to search only in the left or the right sub-tree of that node. Hence searching is very efficient
in a BST.
For example, let us consider the BST shown below. If we have to search for 7, we will first
compare it with the root. Since 7 < 8, search proceeds in the left child i.e. 5. 7>5 so we
search in the right sub-tree of 5 where a match is found . Thus, we have made only 3
comparisons.
Even if the data element is not present in the tree, searching does not take a ling time
since every comparison eliminates one side of the tree. For example, if we are searching for
17, there will be only 3 comparisons made ( 8, 20, 15 )

8
20

5
3
1

15

45

11

node*bst::search(intvalue)
{
if(root!=NULL)
{
if(root>data==value)/*matchfound*/
returnroot;
if(value<root>data)/*searchleftsubtree*/
returnsearch(root>left,value);
else
returnsearch(root>right,value);/*searchrightsubtree*/
}
returnNULL;
}

9 - 36
Trees

Efficiency of Search
Searching in a BST is of the order of O(log2n) and hence it is extremely efficient.
Maximum number of levels in a binary search tree having n nodes is log2 n since there
are 2i-1 nodes in level i. Thus, when we search for an element, maximum log 2 n comparisons
will be made one in each level. Hence the time complexity is O(log2 n).
Example: If there are 1024 values in the tree, search for any element will not take more
than 10 comparisons !.

4 Deletion from a Binary Search Tree


The deletion of a node is not as simple as inserting into the tree. In order to delete a
node, we have to take care of the nodes, which are connected to it and attach them in such a
way that the binary search property is satisfied.
The node to be deleted could be
i.

A leaf node

In such a case, it is easy to remove it. The corresponding link of the parent node has to
be made NULL.

d e le te
15

11

3
5

14

1
15

10 12

6
7

11

13

14
10 12

6
7

13

Deleting a leaf node

ii.

A node having one child

When the node has a single child, the child can be linked to the nodes parent and the
node can be removed.

9 - 37
Trees

8
11

3
1

14

14

15

10 12

11

d e le te

10 12

13

15
13

Deleting a node having one child

iii.

A node having both children

In this case, some rearrangement is needed. One solution is to replace the node with the
rightmost node in its left sub tree or with the leftmost node in its right subtree. Here , we
have replaced it with the leftmost node in its right subtree.

8
11

3
1

10

11

14

12

12

d e le te
1

15
13

14

10

13

15

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 temps parent.

7.

if temp left = = NULL


r = temp right
else

9 - 38
Trees

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

10.

stop

Function
voidbst::delete(intn)
{
node*temp,*parent=NULL,*father,*r,*son;
temp=root;
while((temp>data!=n)&&(temp!=NULL))
{
if(n<temp>data)
{
parent=temp;
temp=temp>left;
}
else
{
parent=temp;
temp=temp>right;

9 - 39
Trees

}
}
if(temp==NULL)
{
printf("Numbernotfound");
return;
}
if(temp>left==NULL)
r=temp>right;
else
if(temp>right==NULL)
r=temp>left;
else
{
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;
}
if(parent==NULL)
root=r;
else
if(temp==parent>left)
parent>left=r;
else
parent>right=r;
deletetemp;
return;
}

Levelwise Display (Breadth First Search)

The Breadth First Search method is a traversal method for a graph. Since a tree is a
type of graph, we can implement this traversal method on a tree as well.

9 - 40
Trees

Breadth First Traversal is level-wise traversal of the tree. We traverse each level of the
tree from left to right starting from the root. It is implemented using a queue. The breadth
first display for the tree,

8
20

5
3

15

45

11

Binary Search Tree

will be
8
5

20

11

15

45

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
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

9 - 41
Trees

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
classqueue
{
intfront,rear;
node*item[MAX];
};

Function
voidbst::levelwise()
{
node*temp=root,*dummy=NULL;
intlevel=0;
queueq;
q.add(temp);
q.add(dummy);
cout<<\nlevel:<<level;
do
{
temp=q.delete();
if(temp!=dummy)
cout<<tempdata;
if(temp==dummy)
{
if(!emptyq())
{
level++;
cout<<\nlevel:<<level;
q.add(dummy);
}
else
{ if(templeft)
q.add(templeft);
if(tempright)
q.add(tempright);
}
}while(!q.empty());

9 - 42
Trees

cout<<Theheightoftree=<<level;
}

THREADED BINARY TREES


In the linked representation of a binary tree having n nodes, there will be a total of 2n
links out of which n+1 links are NULL links.
Example The tree shown has 7 nodes, and 14 links out of which 8 are NULL.

8
5
1
NU LL

15
7

N ULL
NU LL

30

10
N U LL
N ULL

N ULL
N U LL

NU LL

For a larger value of n, this results in a lot of memory wastage.


The main idea here is to replace the NULL links by some useful links so that they may
be used for traversal.
For Example: In the recursive traversal methods, there are a large number of function
calls with NULL pointers. This is time consuming. In non-recursive traversal methods, we
have to make use of a stack for storing previously visited nodes so that we can go back to
them.
Hence, if we utilize the NULL links to store the addresses of some nodes, we could
directly go to these nodes using that pointer and without using a stack.

Concept
In a threaded binary tree, the NULL links are replaced by pointers called threads,
which point to some other nodes of the tree. Depending upon which node a thread points to,
threaded trees can be of three types
1.

Inorder threaded tree

Here, the NULL link of a left child is replaced by a pointer to the node, that comes
immediately before it in inorder.
A NULL right link is replaced by a pointer to the node after it in inorder.

9 - 43
Trees

Example
8
5

10

30

7
Binary Search Tree

Inorder traversal 1 5 7 8

10

30

The inorder threaded tree will be


8
5
1

10
20

7
Inorder-threaded tree

The dotted lines indicate threads.


2.

Preorder threaded tree

A NULL left link is replaced by a thread pointing to a node immediately before it in


preorder.
A NULL right link is replaced by a thread pointing to its succssor in preorder.
Example The tree using preorder threading will be
Preorder :

8 5 1 7 10

20
8
5

10
7

20

Preorder threaded tree

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

9 - 44
Trees
8
5

10

20

7
Postorder threaded tree

We shall be using the inorder threaded binary tree.


Normally, both the links are not replaced by thr1eads. If only the left NULL links are
replaced, it is called a left threaded binary tree and similarly we can have a right threaded
binary tree.
A right in-threaded binary tree

8
5
1

10
20

Right in threaded binary tree

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.
left

lthread

data

rthread

right

classtnode
{
intdata;
tnode*left,*right;
intlthread,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 :
classthreaded;//forwarddeclaration

9 - 45
Trees

classtnode
{
intdata;
tnode*left,*right;
intlchild,rchild;
public:
tnode(intn=0)
{
data=n;
left=right=NULL;
lchild=rchild=0;
}
friendclassthreaded;
};
classthreaded
{
tnode*head;
tnode*root;
public:
threaded()
{
head=newtnode();
root=NULL;
}
//operations
};

1 Creating a threaded binary tree


When a new node has to be added, we have to first determine its position. This is done
in the same way as for a binary search tree.
Once the position is known, the following steps have to be followed.
1.

To attach node as the left child of temp


newnode lchild = newnode rchild = 0;
newnode left = temp left ; /* pull the thread */
newnode right = temp;
temp left = newnode;
temp lchild = 1;

2.

To attach newnode as the right child of temp

9 - 46
Trees

newnode lchild = newnode rchild = 0;


newnode right = temp right ;
newnode left = temp;
temp right = newnode ;
temp rchild = 1;
Usually an extra node called head is used in a threaded binary tree.
These steps can be illustrated in creating an inorder threaded Binary Search tree for the
data .
10

15

30

Data

Tree

head
1.

10

10

head
2.

10
5
head

3.

10

15

15
head
10

4.

15
8

9 - 47
Trees

head
10
5.

30

15
8

30

Function
voidthreaded::create_threaded()
{
tnode*temp,*newnode;
charans;
do
{
cout<<Enterthedata:;
cin>>n
newnode=newnode(n);//constructor
if(root==NULL)
{
root=newnode;
newnode>left=newnode>right=head;
}
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;

9 - 48
Trees

else
if(temp>rchild==0)
{
newnode>right=temp>right;
temp>right=newnode;
temp>rchild=1;
break;
}
else
temp=temp>right;
}
}
cout<<Anymorenodes:;
cin>>ans;
}while(ans==y);
}

2 Inorder Traversal of a Threaded Binary Tree


Once the threaded binary tree is created, it is easy to traverse the tree using the
threads. We shall consider the inorder traversal for a right in-threaded binary tree. As
you know that the inorder traversal is the LDR method i.e. we have to traverse to the
leftmost node from the root and then visit the root followed by the right sub-tree in inorder.
In case of the threaded binary tree, we have to follow the same order and when the node
does not have a right child, we can use the threads which will take us to the correct node.
Algorithm

1. Start
2. Set temp = leftmost of root using the code
while ( temp->left != NULL)
temp = temp->left
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

9 - 49
Trees

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
1

10
7

20

Function

voidthreaded::inorder()
{
tnode*temp=root;
do
{
while(temp>lchild==1)/*movetoleftmostnode*/
temp=temp>left;
cout<<temp>data;
while(temp>rchild==0)&&(temp!=head)/*temphasrightchild*/
temp=temp>right;
if(temp==head)
return;
temp=temp>right;/*usethread*/
}while(temp!=head);
}

3 Preorder Traversal of a Threaded Binary Tree


In the previous section we saw how a right in-threaded binary tree can be traversed in
the inorder. We can also traverse an inorder threaded binary tree in preorder. The following
algorithm shows the steps for the preorder traversal.

9 - 50
Trees
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.
voidthreaded::preorder()
{
while(1)
{
cout<<root>data;
while(root>lchild==1)
{
root=root>left;
cout<<root>data;
}
if(root>rchild==0)

9 - 51
Trees

root=root>right;
else
{
while(root>rchild==1)
{
if(root>right==head)
return;
root=root>right;
}
if(root>rchild==1)
root=root>right;
}
}
}

Postorder Traversal of a Threaded Binary Tree


In the previous section we saw how a right in-threaded binary tree can be traversed in
the preorder. Postorder traversal is more complicated compared to inorder and preorder
traversals. For postorder traversal, we will need the left threads also because we have to
travel from the right child to the parent using the left thread. Thus, we need a fully
threaded binary tree.
The postorder of the following tree is : 1

20

10

8
5
1

10
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.Loopwhileallnodeshavenotbeenvisited
CaseNextAction
GoLeft:
Traverseleftsubtreeifitexists

9 - 52
Trees

Returntonode
NextAction=GoRight
GoRight:
Traverserightsubtreeifitexists
Returntonode
NextAction=VisitNode
VisitNode:
VisitNode
FindParentofNode
//SetNextActionasgivenbyparent
IfNodeisleftchildofparentthenNextAction=GoRight
IfNodeisrightchildofparentthenNextAction=VisitNode
Ifparentistherootthen
GotoStep4.
Endcase
Endloop
4Stop.

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.
On completion of traversing a left subtree NextAction will be set to GoRight.
On completion of traversing a right subtree NextAction will be set to VisitNode
One can determine which of these cases has occurred by using threads and at the same
time find the node that is the parent node of the last one visited.
For example:
If we are in a left subtree then we find the parent by moving right as far as possible in
the subtree and then take a right thread. If the left child of the node which we have reached
is the original one then we have located the parent and are in the left subtree.

9 - 53
Trees

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.

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

RS1

M2

RS2

Mn

RSn

9 - 54
Trees

Here, M1, M2 etc are the moves made and RS1RSn 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.

Expression and Decision Trees

We have studied the concept of an expression tree in Section 2.2. It is a tree which
represents an expression. The leaf nodes represent the operands and the internal nodes
represent operations.
The expression can be evaluated by applying the operator in the parent to the result of
the left and the right sub trees.
Another application of trees is in decision making. In many applications, a decision
needs to be taken at a certain point depending upon a certain situation. In such cases, the
choice of the decision taken will affect the further processing. Hence, it would be better if we
could find out what would be the consequences of a certain decision and accordingly decide
what decision to take.

9 - 55
Trees

What is a decision tree?


A decision tree is a tree which represents a set of decisions by which we can get a
solution to a problem. Decision Trees are excellent tools for helping you to choose between
several courses of action. They provide a highly effective structure within which you can lay
out options and investigate the possible outcomes of choosing those options. They also help
you to form a balanced picture of the risks and rewards associated with each possible course
of action.
For example, consider the following decision tree which shows the steps carried out for
finding out the largest among three numbers.
A>B
Yes

No

A>C
Yes
A

B>C
No
C

The leaf nodes represent the solutions.

Yes
B

No
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
a) The maximum number of nodes on level i of a binary tree is 2i-1 , i 1and

9 - 56
Trees

b) The maximum number of nodes in a binary tree of depth k is 2k - 1, k 1


Soln:
Proof: a)
Induction Base: If the root is the only node, we know that the root is the only node at level
1. Hence, maximum number of nodes on level i=1 is 2i-1.
Induction hypothesis:
For all j , 1 j < i, the maximum number of nodes on level j is 2j-1.
Induction Step:
The maximum number of nodes on level i-1 is 2 i-2. Since each node in a binary tree has
maximum degree 2, this means the maximum nodes on a level i is 2 times the maximum
number of nodes on level i-1. On level i-1, there are 2 i-2 nodes. Hence on level i, there will be
2*2i-2 nodes i.e. 2i-1 nodes.
b) On level i, there are maximum 2i-1 nodes. Since there are a total of k levels, the total
number of nodes in a binary tree will be
k

total number of nodes on level i

i 1

2 i-1

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.
Prefix

Position in infix

Root of the tree.

Left of *

Left of *, Left of +

Left of *, Right of +

Right of *. Hence it is the right child of *

9 - 57
Trees

Right of *, Left of

Right of *, Left of -, Left of +

Right of *, Left of -, Right of +

Right of *, Right of -

Hence, the tree will be as follows:

*
-

+
b

3. How many ancestors does a node at level n in a binary tree have?


Soln: If a node is at level n, then there are n-1 levels above Hence, the node will have n-1
ancestors one at each level. For example, in the tree shown below, the element 7 is at level
3. Hence, it has two ancestors, 5 and 8.
8
20

5
3

15

25

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.
AlgorithmCheck_strictly(NODE*root)
//rootisapointertotherootofthebinarytree
//ThealgorithmreturnsTrueorFalse
{
if(root!=NULL)

9 - 58
Trees

{
if(root>left!=NULL)&&(root>right!=NULL)||
(root>left==NULL)&&(root>right==NULL)then
{
if(Check_strictly(root>left))then
returnCheck_strictly(root>right);
}
else
returnFalse
}
returnTrue;
}
5. Compare sequential and Linked Representation of a binary tree.
Soln:
Factor

Static

Dynamic

Data Structure used

Array

Linked List

Memory

Since an array
memory is fixed

used,

Memory can be allocated


and de-allocated during runtime.

Complexity of Operations

Operations like insertion,


deletion cannot be performed
easily

Operations can be performed


easily.

Advantages

Simple implementation.

No limitation on memory.
Useful when the are a lot of
operations
have
to
be
performed on the tree

Application

Preferable when the tree is a


complete or almost complete
binary tree

Suited for all types of trees.

is

6. What is the difference in the search operation carried out on a binary tree and
a binary search tree?

9 - 59
Trees

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.
NODE*parent_node(NODE*root,intn)
{
NODE*temp=root,*parent=NULL;
while((temp>data!=n)&&(temp!=NULL))
{
if(n<temp>data)
{
parent=temp;
temp=temp>left;
}
else
{
parent=temp;
temp=temp>right;
}
}
if(temp==NULL)
{
printf("Numbernotfound");
returnroot;
}
if(parent==NULL)
printf(Thenodeistherootofthetree);
returnroot;
}

9 - 60
Trees

Anda mungkin juga menyukai