0% found this document useful (0 votes)
59 views

Unit 2 Tree

1) Trees are non-linear data structures that are used to represent hierarchical relationships. They allow modeling of one-to-many relationships. 2) A tree consists of nodes connected by edges. It has a root node with zero or more child nodes below it. Child nodes may also have their own child nodes. 3) Trees have various properties like internal/leaf nodes, parent/child relationships, subtrees, levels, height/depth, binary/non-binary types. Binary search trees arrange nodes to keep left subtrees smaller than the parent and right subtrees larger.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
59 views

Unit 2 Tree

1) Trees are non-linear data structures that are used to represent hierarchical relationships. They allow modeling of one-to-many relationships. 2) A tree consists of nodes connected by edges. It has a root node with zero or more child nodes below it. Child nodes may also have their own child nodes. 3) Trees have various properties like internal/leaf nodes, parent/child relationships, subtrees, levels, height/depth, binary/non-binary types. Binary search trees arrange nodes to keep left subtrees smaller than the parent and right subtrees larger.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 55

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

Motherboard Peripherals 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.

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

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

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)

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.

Strictly Binary Tree


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

B C

D E

F G
Strictly Binary Tree

Full Binary Tree


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

B C

D E F G
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. A complete binary tree is a
binary tree in which every level, except possibly the last, is completely filled, and all nodes are
as far left as possible.
9 - 22
Trees

Maximum Nodes in a binary tree


The maximum number of nodes on level i is 2i-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 = 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

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

B C

D E F G

H I J
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.
A A

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

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.
9 - 22
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

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

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


Since the references now access either the first child or successive siblings,
the process must use this type of information rather than magnitude as was
the case for the binary search tree. Note that the resulting tree is a
binary tree but not a binary search tree.
Process of converting normal tree into binary tree:

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.

The final binary tree will be as follows :

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

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.

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

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


The tree representation will be:
0 1 2 3 4
A B C D E F G
9 - 22
Trees
0
A

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

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) = (9–1) /2
= 8/2 = 4
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.
9 - 22
Trees
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

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

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

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.

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

Binary Tree node

The linked representations of some binary trees are shown below.

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 definitions for Binary Tree


This node structure for the binary tree can be defined as follows:

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

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 - 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 &);
};

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

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.

1 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

void tree::preorder()
{
//Calls a private member function to traverse
preorder(root);
}

void tree::preorder(node * currentnode)


{
if (currentnode != NULL)
{
cout<< currentnode  data; /* D */
preorder(currentnode  left); /* L */
preorder(currentnode  right); /* R */
}
}

2. Recursive Inorder Traversal

void tree::inorder()
{
//Calls a private member function to traverse
inorder(root);
}

void tree::inorder(node * currentnode)


{
if (currentnode != NULL)
{
inorder(currentnode  left); /* L */
cout << currentnode  data; /* D */
inorder (currentnode  right); /* R */
}
}
3. Recursive Postorder Traversal
9 - 22
Trees
void tree::postorder()
{
//Calls a private member function to traverse
postorder(root);
}

void tree::postorder (node * currentnode)


{
if (currentnode!= NULL)
{
postorder(currentnode  left); /* L */
postorder(currentnode  right); /* R */
cout << currentnode  data; /* D */
}
}

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

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.


9 - 22
Trees

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

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

Temp Step Number Stack ( contains Output


points to node address of )
+ 3 +
* 3 +, *
a 3 +, * , a
a 5 +, * a
* 5 + a*
b 3 +b a*
b 5 + a*b
+ 5 Empty a*b+
c 3 C a*b+
c 5 Empty a*b+c
NULL Empty a*b+c

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;

cout<<”The non recursive inorder traversal is :”<<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.
9 - 22
Trees

Example: Preorder = ABDEFGC


Inorder = DBFEGAC
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 A’s left subtree, attach it to the left of A.
D is the next in preorder. Since it is also in A’s subtree, we have to check its position with
respect to B. It is in B’s left sub-tree in inorder. Attach it to left of B.
E is next in preorder. E is in A’s left subtree, it is to the right of B. Attach it to the right of B.
F is in A’s 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 A’s 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 A’s right sub-tree. Attach it as the right child. The final tree is as shown.
A

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.

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.
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.
9 - 22
Trees
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 11.
Else
Move temp to its left. Go to step 8
10. If ans = right
If temp does not have a right child
Attach node to its right of temp. Go to step 11.
Else
Move temp to right. Go to step 8
11. Ask user “Any more nodes?”. Accept answer.
12. If answer = Yes, Go to step 3.
13. Stop.

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.

void tree::insert(char ch)


{
node *temp;
node * newnode = new node(c);
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)
{ 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
}

node * tree::copy(node *root1, node *root2)


{
//create a tree with root2 the same as tree with root1
if (root1 != NULL)
{
root2 = new node(root1->data);
root2  left = copy(root1 left);
root2  right = copy (root1right);
return root2;
}
else
return NULL;
}

3 Mirroring a Binary Tree


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

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);
}

node * tree :: mirror(node * root1, node *root2)


{
node * root2=NULL;
if (root1 != NULL)
{
root2 = new node(root1->data);
root2  left = mirror(root1 right);
root2  right = mirror(root1left);
}
return root2;
9 - 22
Trees
}
The mirrored tree can be displayed by using any tree traversal method.

4 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.
int tree::countnodes ()
{
return countnodes(root);
}
int tree::countnodes(node *root)
{
static int count = 0 ;
if (root ! = NULL)
{
count ++;
countnodes (root  left);
countnodes (root  right)
}
return count ;
}

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

int tree::countleafnodes ()
{
return countleafnodes(root);
}

int tree::countleafnodes (node * root)


{
static int countleaf = 0 ;

if (root == NULL)
return countleaf;
if (root  left == NULL && root  right == NULL)
return ++ countleaf;
countleafnodes (root left);
countleafnodes (root  right);
}
9 - 22
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 15 5 1 7 13
ro o t 10 will be the root
10 10

10 20 > 10. Hence it is the


right child
20
20

10 15 > 10. But 10 already


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

10 5<10. Thus, 5 is the left


child of 10

5 5 20

1
9 - 22
Trees

10 1 < 10. But 10 already


has a left child. So
compare 1 with 5.
5 20
1 < 5.Hence 1 is the left
child of 5.
1

10 6 < 10. Thus left sub-tree.


6>5. Thus 6 is the right
5 20 child of 5.
6

1 6 15

10 13 > 10. Right sub-tree


13 < 20. Left sub-tree
5 20 13<15. Left child.
13
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

void bst :: create()


{
NODE * newnode, *temp ;
int n;
char ans ;
do {
newnode = getnode();
cout<<“Enter the element to be inserted :”;
cin>>n;
newnode  data = n;
newnode  left = newnode  right = NULL;

/* attach newnode to the tree */


if (root == NULL)
root = newnode ;
else
{
temp = root;
while (1)
{
if (n < temp  data)
if (templeft==NULL)/* temp does not have left child */
9 - 22
Trees
{ temp  left = newnode; break; }
else
temp = temp  left ; /* Move temp left */
else
if (temp  right)== NULL)
{ temp  right = newnode ; break; }
else
temp = temp  right;
} /* end while */

cout<<“\n Any more numbers ? :”;


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

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

Void bst:: insert(int n)


{
node *temp, *newnode;
newnode = new node(n);
if (root == NULL)
root = newnode ;
else
{
temp = root;
while (1)
{
if (n < temp  data)
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;
} /* end while */
}
}
9 - 22
Trees

3 Searching an element in Binary Search Tree


Unlike searching in an ordinary binary tree, to search for a specific data element, we don’t
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 sub-tree 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

5 20

3 7 15 45

1 11
node *bst::search(int value)
{
if(root != NULL)
{
if ( root->data == value ) /* match found */
return root;

if ( value < root->data) /* search left subtree */


return search(root->left, value);
else
return search(root->right, value); /* search right subtree */
}
return NULL;
}
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 log2 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


9 - 22
Trees
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.
8 8
d e le te
3 11 3 11
15
1 5 9 14 1 5 9 14

10 12 15
6 6 10 12

7 13 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 node’s parent and the node
can be removed.
8 8

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

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.
9 - 22
Trees

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

void bst::delete( int n)


{
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;
}
}
if(temp==NULL)
{
printf("Number not found");
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 ;
}
9 - 22
Trees

if(parent==NULL)
root=r;
else
if (temp == parent -> left)
parent -> left = r;
else
parent-> right = r;
delete temp;
return ;
}

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

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 ()
{

node* temp = root, *dummy=NULL;


int level = 0;
queue q;
q.add(temp);
q.add(dummy);
cout <<“\n level :” << level;
do
{
temp = q.delete();
if (temp != dummy)
cout << temp  data;
if (temp == dummy)
{
if (!emptyq())
{
level++;
cout <<“\n level :” << level;
q.add(dummy);
}
else
{ if (temp  left)
q.add(temp  left);
if (temp  right)
q.add(temp  right);
9 - 22
Trees
}
} while (!q.empty());
cout<<”The height of tree= “ <<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 15

1 7 10 30

NULL NULL NULL NULL


NULL NULL NULL NULL

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.
Example
8
5 10

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

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

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

8
5 10

1 7 20

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
9 - 22
Trees

8
5 10

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

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 threaded; //forward declaration

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

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.
9 - 22
Trees
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
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 5 15 8 30
9 - 22
Trees
Data Tree

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’);
}

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

while(temp->rchild == 0)&&(temp!=head) /* temp has right child */


temp = temp->right;
if(temp==head)
return;
temp=temp->right; /* use thread */
} while(temp != head);
}

3 Preorder Traversal of a Threaded Binary Tree


9 - 22
Trees
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.

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

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 7 5 20 10 8

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.

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.

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

RS1 RS2 RSn

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.

2 Expression and Decision Trees


9 - 22
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.
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 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

a) The maximum number of nodes on level i of a binary tree is 2i-1 , i  1and


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


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

Prefix Position in infix


* Root of the tree.
+ Left of *
a Left of *, Left of +
b Left of *, Right of +
- Right of *. Hence it is the right child of *
+ Right of *, Left of –
c Right of *, Left of -, Left of +
d Right of *, Left of -, Right of +
e Right of *, Right of -
Hence, the tree will be as follows:
9 - 22
Trees

*
+ -

a b + e

c d

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

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.

Algorithm Check_strictly ( NODE * root)


// root is a pointer to the root of the binary tree
// The algorithm returns True or False
{
if(root != NULL)
{
if(root->left!=NULL)&&(root->right!=NULL)||
(root->left==NULL)&&(root->right==NULL) then
{
if( Check_strictly(root->left)) then
return Check_strictly(root->right);
}
else
return False
}
return True;
}
9 - 22
Trees

5. Compare sequential and Linked Representation of a binary tree.


Soln:
Factor Static Dynamic
Data Structure used Array Linked List
Memory Since an array is used, Memory can be allocated and
memory is fixed de-allocated during run-time.
Complexity of Operations Operations like insertion, Operations can be performed
deletion cannot be performed easily.
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 Suited for all types of trees.
complete or almost complete
binary 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.

NODE *parent_node(NODE *root, int n)


{
NODE *temp=root, *parent=NULL;
while((temp->data!=n) && (temp!=NULL))
{
if(n<temp->data)
{
parent=temp;
9 - 22
Trees
temp=temp->left;
}
else
{
parent=temp;
temp=temp->right;
}
}
if(temp==NULL)
{
printf("Number not found");
return root;
}
if(parent==NULL)
printf(“The node is the root of the tree “);
return root;
}

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy