You are on page 1of 12

Data Structures & Algorithms

SECTION 6
OBJECTIVES: At the end of the session, the student is expected to be able to
1. Define a binary tree and related concepts.
2. State important properties of binary trees.
3. Give examples of different types of binary trees.
4. List the nodes of any given binary tree in preorder, inorder and postorder
5. Design algorithms which center on the idea of traversing a binary tree, e.g. ,
constructing a binary tree given its nodes in preorder and inorder, traversing a
binary tree in level order, etc.
6. Write EASY procedures to implement the algorithm in 5.

DISCUSSION:

Thus far we have considered only linear data structures, viz., the stack and the
queue, which are represented in the memory of a computer either by a sequentially
allocated vector or a singly-linked linear list. We will now consider a very important
nonlinear data structure – the binary tree.

The binary tree is utilized in a wide variety of applications, including searching


(binary search trees), sorting (heapsort), efficient encoding of strings (Huffman’s code),
etc. They are used to implement the priority queues, decision tables, and the like.
Algorithms for traversing binary trees underlie various procedures (for marking, copying,
printing, etc.) for other structure such as generalized lists and multilinked structures.

What is a binary tree?


Following Knuth, we define a binary tree as a finite set of nodes which is either
empty, or consists of a root and two disjoint binary trees called the left and right subtrees
of the root.

Section 6 Page 1 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

Shown below are six different binary trees:

A
Λ A A A
A
(null
Binary tree) B
B
B B C

D E F G

(a) (b) (c) (d) (e) (f)

Example (a) depicts the especially important null or empty binary. In examples (b) to (f),
node A is the root of the binary tree. In (b), both left and right subtrees of the root are
null; while in (c) and (d), the right and left subtrees, respectively, are null. For the binary
tree in (e), all right subtrees are null; while for that in (f), each node either has two
subtrees or none at all. Later, we will give names to these and other types of binary
trees.

Consider now the binary tree shown in Fig. 1.

A
………….. Level 0

B C …………… Level 1

D E F G ……. Level 2

H I J ……………………. Level 3

Fig. 1 A binary tree

Node A is the root of the binary tree. The left and right subtrees of node A are the
binary trees rooted at nodes B and C, respectively. In turn, the left and right subtrees of
node B are the binary trees rooted at D and E, respectively. And so on.

Section 6 Page 2 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

The number of non-null subtrees of a node is called its degree. Thus, nodes A, B,
C and D have degree 2; node E has degree 1; and nodes F, G, H, I and J have degree
zero. Nodes with degree zero are called leaves or terminal nodes.

The level of a node is defined by specifying that the root of the binary tree is at
level 0, the roots of its subtrees are at level 1, and so on. The height or depth of a binary
tree is the level of the bottommost node(s), which is also the length of the longest path
from the root to any leaf. The binary tree in Fig. 1has height (or depth) 3.

In addition to botanical terms (tree, root, leaf, branch) and spatial terms (left,
right, top, bottom), we will also use the familial terms (father, son, brother, descendant,
ancestor) in describing binary trees and operations on them. We will freely mix
metaphors involving these three classes of terms, as in the phrase left son of the root.

In the binary tree of Fig. 1, node A is the father of nodes B and C, and nodes B
and C are the sons of node A. Nodes B and C are, of course, brothers. Nodes D, E, H, I
and J are the descendants of node B; nodes A, B and D are the ancestors of node H.

Some properties of binary trees

1. The maximum number of nodes at level n of a binary tree is 2 ⁿ, n > 0.

2. The maximum number of nodes in a binary tree of depth k is


k
Σ 2ⁿ = 2 -1.
n=0

3. If n0 is the number of terminal nodes and n2 is the number of nodes of


degree 2 in a binary tree, then n0=n2 + 1.

Proof: Let n= total number of nodes


n1= number of nodes of degree 1
nB= number of branches

Then
(a) N = n0 + n1 + n2 (obviously)
= nB + 1 (since each node, except the root, has a branch leading
to it)

Section 6 Page 3 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

(b) = n1 + 2n2 + 1 (since a node of degree 1 has one branch emanating


from it, and
a node of degree 2 has two)

Subtracting (b) from (a) and rearranging terms, we obtain

n0 = n2 + 1 Q.E.D.

4. The number of distinct binary trees on n nodes, Bn, is

Bn = ___1___ 2n ≈ ___4n___ + 0(4n n-6/2)


n + 1 (n) n 3/2 √π

2n
where ( ) = 2n (2n-1)(2n-2)…(n+1)
n n(n-1)(n-2)…1

The derivation of the formula for bn is quite involved. (See, for example, Standish[1980],
pp. 54-57.)

A nomenclature for binary trees

Certain types of binary trees are used in the analysis of the time complexity of a
number of searching algorithms and also in the implementation of a particular sorting
technique (heapsort). Unfortunately, there is no agreement among various authors as to
the names given to these binary trees. To add to the confusion, the same name is
sometimes used to refer to two different types of binary tree. For our purposes, we will
adopt, and consistently use, the following nomenclature for binary trees:

1. A right (left)-skewed binary tree is a binary tree in which every node has no left
(right) subtree. For a given number of nodes, a left or right-skewed binary tree
has the greatest depth.

A A

B B

C
C

A left-skewed binary tree A right-skewed binary tree

Section 6 Page 4 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

2. A strictly binary tree is a binary tree in which every node has either two subtrees
or none at all.
A

B C

D E

F G

A strictly binary tree

3. A full binary tree is a strictly binary tree in which all terminal nodes lie at the
bottommost level. For a given depth, the full binary tree has the maximum
number of nodes.

B C

D E F G

H I J K L M N O

A full binary tree

4. A complete binary tree is the binary tree which results when zero or more nodes
are deleted from a full binary tree in reverse level order, i.e., from right to left,
bottom to top.

B C

D E F G

H I J L
K

A complete binary tree

Binary tree traversals

Since a binary tree is structurally non-linear, a sequential processing of the


information contained in its nodes requires a procedure that visits the nodes of the
binary tree in a linear fashion such that each node is visited exactly once, where to visit

Section 6 Page 5 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

a node means to perform the computations (not necessarily numerical) local to the node.
Such a process is called a traversal.

In a binary tree, there are three distinct and disjoint entities: a node (or root), its
left subtree (which may be null) and its right subtree (which may be null). Let us denote
these entities as N, L and R, respectively. The order in which we process these entities,
recursively, defines a particular traversal method. There are six different sequences:
NLR, NRL, LNR, LRN, RNL and RLN. If we insist that L should always precede R, then
we are left with three traversal orders: NLR-recursive, or preorder, LNR-recursive or
inorder, and LRN-recursive or postorder. The prefixes pre, in and post specifies the
position of the root in the order of processing. The three traversal methods are defined
as follows:
Definition: If the binary tree is empty, do nothing (or consider the traversal as
‘done’); else
1. Preorder traversal
Visit the root.
Traverse the left subtree in preorder.
Traverse the right subtree in preorder.
2. Inorder traversal
Traverse the left subtree in inorder.
Visit the root.
Traverse the right subtree in inorder.
3. Postorder traversal
Traverse the left subtree in postorder.
Traverse the right subtree in postorder.
Visit the root.

Note that each of the above definitions is recursive. This is to be expected since the
binary tree is itself a recursively defined structure.

If, in the above definitions, we interchange ‘left’ and ‘right’, then we obtain three
new traversal orders which we may call converse preorder, converse inorder and
converse postorder. Still another way to traverse a binary tree is in level order, that is,
visit the nodes from top to bottom, left to right.

Section 6 Page 6 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

Example 1.
Preorder:A B C D E F G H I J
A Inorder:C B D E F A G F I H J
F Postorder:C E D B G I J H F A
B
H
C D G

E I J

Example 2.
-
Preorder: - + A * / B ^ C D E F
+ F Inorder: A + B / C ^ D * E - F
A * Postorder: A B C D ^ / E * + F -
E
/

B ^

C D

Example 2 depicts the binary tree representation of the arithmetic expression


A+ _B_ * E – F. The preorder, inorder and postorder sequences of the nodes of the binary
C^D
tree correspond to the prefix, infix and postfix forms of the given expression, respectively.

Binary tree representation in computer memory

Thus far we have been looking at a binary tree in the abstract, independent of a specific
representation. However, to realize the traversal and other algorithms on binary trees on a
computer we need to represent a binary internally in computer memory. The most natural way to
do this is to use the link addressing method where each node has structure

LSON DATA RSON

where the LSON and RSON fields contain pointers to the left and right subtrees of the
node, respectively; and the DATA field contains the data local to the node. This
representation mimics the way we draw a binary tree on paper. Using this
representation, the binary tree of Example 1 is depicted, thus:

Section 6 Page 7 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

B F

Λ C Λ Λ D Λ G Λ H

Λ E Λ Λ I Λ Λ J Λ

Fig.2 The linked representation of a binary tree

The pointer variable T points to the root node and, effectively, to the entire binary tree.
Note that from the root node all nodes of the binary tree are accessible via the LSON
and RSON links. In general, we will refer to a binary tree by the pointer to its root node;
e.g., the binary tree of Fig. 2 will be called binary tree T. The condition S= A means the
binary tree S is empty.

For any given node a, this linked representation of a binary tree answers the
question “Who are your sons?” but not the question “Who is your father?”. We ask the
first question as we descend a binary tree (from the root to the leaves), and we ask the
second question when we climb up a binary tree. Traversal and other algorithms on
binary trees invariably climbing down and up a binary tree. In the absence of a Father
link, we need to devise ways to locate the fathers. One easy way to do this is to use a
stack; other techniques, such as the use of threads, link inversion, etc., will be discussed
in subsequent sessions.

Linked representation is by no means the only way to represent binary trees. In


the next session we will consider an efficient sequential representation scheme for a
complete binary tree.

EASY procedures to implement the traversal algorithms

We will now consider the implementation of the traversal algorithms as EASY


procedures using the linked representation of a binary tree as depicted in Fig. 2. The
recursive versions of the procedures follow directly from the recursive definitions of the

Section 6 Page 8 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

traversal orders; the non-recursive versions, though less concise, give a better insight
into the traversal process, which is of considerable importance in understanding and
developing algorithms on binary trees.

Procedure INORDER (T)


//Prints the node labels of binary tree T in inorder//
node (LSON, DATA, RSON)
if T <> A then call INORDER(LSON(T))
output DATA (T)
call INORDER (RSON(T))
end INORDER

Note that the procedure is essentially a straightforward coding of the definition of


inorder traversal. Since this is our first encounter with a recursive procedure on binary
trees, it would be instructive to trace the actions of the procedure when applied to a
sample binary tree, such as the one shown below:
T
a1:
A
a2: a3:
B Λ C
a4: a5: a6:
Λ D Λ Λ E Λ Λ F Λ

call INORDER (a1) //a1= T//


call INORDER(a2) //a2=LSON(a1)//
call INORDER(a4) //a4=LSON(a2)//
call INORDER(Λ) // Λ =LSON (a4)//
output DATA(a4) //print D//
call INORDER(Λ) // Λ =RSON(a4)//
output DATA(a2) //print B//
call INORDER(Λ) // Λ =RSON(a2)//
output DATA(a1) //print A//
call INORDER(a3) //a3=RSON(a1)//
call INORDER(a5) //a5=LSON(a3)//
call INORDER(Λ) // Λ =LSON(a5)//
output DATA (a5) //print E//
call INORDER (Λ) // Λ =RSON(a5)//
output DATA(a3) //print C//
call INORDER(a6) //a6=RSON(a3)//
call INORDER (Λ) // Λ =LSON(a6)//
output DATA(a6) //print F//
call INORDER(Λ) // Λ =RSON(a6)//
Section 6 Page 9 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

The non-recursive version for inorder traversal is given below. The procedure
uses a sequential stack to store the addresses of nodes whose left subtrees are
travesed (in inorder) so that, subsequently, each such node can be visited and its right
subtree traversed (in inorder). Study the procedure carefully.

procedure INORDER(T)
//Non-recursive procedure to print the node labels of binary tree T. Uses a sequential
stack of maximum size 100.//
array S(1:100)
node(LSON, DATA, RSON)
αÅT
top Å 0
loop
while α <> A do
call SPUSH (S, 100, top, α)
α Å LSON(α)
endwhile
if top=0 then return
else [call SPOP(S,100,top,α)
output DATA(α)
αÅ RSON(α)]
forever
end INORDER

The recursive procedures for preorder and postorder traversal are readily coded
from the corresponding recursive definitions. The non-recursive version for preorder
traversal differs from that for inorder traversal only in the position of the output
statement. Writing these procedures is left as an exercise.

The non-recursive procedure to implement postorder traversal needs a little more


planning. In preorder and inorder traversal, a node is encountered twice: (a) on going
down leftward as its left subtree is traversed, at which point it is visited and placed in the
stack (if preorder) or simply placed in the stack (if inorder), and (b) on going up from the
left after its left subtree has been traversed at which point it is unstacked and its right
subtree traversed (if preorder) or unstacked, visited and its right subtree traversed (if
inorder). In postorder traversal, each node is encountered thrice: (a) on going down
leftward as its left subtree is traversed, at which point it is stacked; (b) on going up from
the left after its left subtree has been traversed, at which point it is unstacked (so that its
right subtree can be located) and then placed in the stack anew (so it can be visited
later); and (c) on going up from the right after its right subtree has been traversed, at

Section 6 Page 10 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

which point it is unstacked the second time and finally visited. In summary, for preorder
and inorder traversal, a node is stacked-unstacked once, whereas for post order
traversal a node is stacked-unstacked twice. Thus, for postorder traversal, we either use
two stacks, or a single stack plus a tag bit to differentiate between the first and second
instances that a node is placed in the stack.

The EASY procedure POSTORDER given below uses a single sequential stack
and the – and + signs as tags. A node, say node a, is placed in the stack for the first
time as –a, and for the second time as +a. Study the procedure carefully.

procedure POSTORDER (T)


//Prints the node labels of binary tree T in postorder//
array S(1:100)
node(LSON, DATA, RSON)
αÅT
topÅ 0
1: while α <> A do
call SPUSH(S,100,top,-α)
αÅ LSON(α)
endwhile
2: if top = 0 then return
else [call SPOP (S,100,top,α)
if α < 0 then [α Å - α
call SPUSH (S,100,top, α)
α Å RSON(α)
go to 1]
else [output DATA(α)
go to 2]]
end POSTORDER

Applications of the traversal algorithms to the other operations on binary trees

1. Making a duplicate copy of a binary tree: To make a copy of a binary tree, say T,
represented as in Fig. 2, we can use postorder traversal (review the recursive
definition given above) as follows: for every node, say node a, in T

Traverse the left subtree of node a in postorder and make a copy of it.
Traverse the right subtree of node a in postorder and make a copy of it.
Make a copy of node a and attach copies of its left and right subtrees.

The following EASY procedure formalizes the idea:


Section 6 Page 11 of 12
Jennifer Laraya-Llovido
Data Structures & Algorithms

procedure COPY(T)
//Given a binary tree T, COPY makes a duplicate copy of T and returns a pointer
to the root node of the constructed copy//
node(LSON, DATA, RSON)
αÅA
if T<>A then [βÅ COPY (LSON(T))
α Å COPY (RSON(T))
call GETNODE (α )
DATA (α ) Å DATA (T)
LSON (α ) Å β
RSON (α) Å α]
return (α)
end COPY

To invoke procedure COPY, we can write

SÅ COPY (T)

2. Determining the equivalence of two binary trees: two binary trees are equivalent if one
is an exact duplicate of the other, such as binary trees S and T above. To determine
whether two binary trees, say S and T, are equivalent, we can apply preorder traversal
(review the recursive definition given above) as follows: for every corresponding nodes,
say node a and node b, in S and T
Check whether node a and node b contain the same data
Traverse the left subtrees of node a and node b in preorder and check whether
they are equivalent
Traverse the right subtrees of node a and node b in preorder and check whether
they are equivalent
If at any point in the process it is discovered that S and T are not equivalent, the test is
terminated. The following EASY procedure formalizes the idea:

Procedure EQUIV(S,T)
//Given two binary trees S and T, EQUIV returns true if S and T are equivalent; else, it
returns false.//
node(LSON,DATA,RSON)
ansÅ false
case
:S = A and T=A: ans Å true
:S<> A and T <> A: [ans Å (DATA(S)= DATA (T))
if ans then ans Å EQUIV(LSON(S), LSON(S))
if ans then ans Å EQUIV(RSON(S), RSON(S))
endcase
return (ans)
end EQUIV
Section 6 Page 12 of 12
Jennifer Laraya-Llovido

You might also like