You are on page 1of 86

Chapter 18

Trees
General Trees
• Trees can be defined in two ways:
– Nonrecursively
• More direct technique
– Recursively
• Allows to write simple algorithms to
manipulate trees

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-2


Definitions
• Nonrecursively, a tree consists of a set of
nodes and a set of directed edges that
connect pairs of nodes.
• Here we consider only rooted trees.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-3


Definitions (2)
• One node is distinguished as the root.
• Every node c, except the root, is connected
by an edge from exactly one other node p.
Node p is c's parent and c is one of p's
children.
• A unique path traverses from the root to
each node. The number of edges that must
be followed is the path length.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-4
Definitions (3)
• A tree with N nodes must have N – 1 edges
because every node except is the length of
the path from the root the parent has an
incoming edge.
• The depth of a node in a tree is the length of
the path from the root to the node.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-5


Definitions (4)
• Thus the depth of the root is always 0 and
the depth of any node is 1 more than the
depth of its parent.
• The height of the node in a tree is the length
of the path from the node to the deepest
leaf.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-6


Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-7
Definitions (5)
• Thus the height of E is 2.
• The height of any node is 1 more than the
height of its maximum-height child.
• Thus the height of a tree is the height of the
root.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-8


Definitions (6)
• Nodes with the same parent are called
siblings ( B, C, D, and E are all siblings).
• If there is a path from node u to node v,
then u is an ancestor of v is a descendant of
u.
• If u ≠ v, then u is a proper ancestor of v and
v is a proper descendant of u.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-9


Definitions (7)
• The size of a node is the number of
descendants the node has (including the node
itself).
• Thus the size of B is 3, and the size of C is 1.
• The size of a tree is the size of the root.
• Thus the size of the tree is the size of its root
A or 11.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-10


Recursive Tree
• An alternative definition of the tree is recursive
• Either a tree is empty or it consists of a root and
zero or more nonempty subtrees T1, T2, ..., Tk,
each of whose roots are connected by an edge
from the root, as illustrated.
• In certain instances, we may allow some of the
subtrees to be empty.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-11


Recursive Tree (2)
• One way to implement a tree would be to
have in each node a link to each child of the
node in addition to its data.
• However, as the number of children per
node can vary greatly and it is not known
in advance, making the children direct links
in the data structure, might not be feasible
(to much wasted space).
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-12
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-13
First Child/next Sibling
• The solution, called the first child/next
sibling method, is simple.
• Keep the children of each node in a linked
list of tree nodes, with each node keeping
two links, one to its leftmost child (if it is
not a leaf) and one to its right sibling (if it is
not the rightmost sibling).
• Arrows that point downward are firstChild
links and arrows that point left to right are
nextSibling links.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-14
First Child/next Sibling (2)

• In this tree, node B has both a link to a


sibling (C) and a link to a leftmost child (F)
• Some nodes have only one of these links
and some have neither.
• Given this representation, implementing a
tree class is straightforward.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-15


First Child/next Sibling (3)

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-16


Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-17
An Application: File Systems
• Figure 18.4 shows a typical directory in the
Unix file system. The root of this directory
is mark. (The asterisk next to the name
indicates that mark is itself a directory.)
• Mark has three children: books, courses,
and .login, two of which are themselves
directories.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-18


Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-19
File Systems (2)
• Thus mark contains two directories and
one regular file.
• The filename mark/books/dsaa/chl is
obtained by following the leftmost child
three times.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-20


File Systems (3)
• Each / after the first name indicates an edge;
the result is a pathname.
• If the path begins at the root of the entire
file system, rather than at an arbitrary
directory inside the file system, it is a full
pathname; otherwise, it is a relative
pathname (to the current directory).

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-21


File Systems (4)
• This hierarchical file system is popular
because it allows users to organize their
data logically.
• Two files in different directories can share
the same name because they have different
paths from the root and thus have different
full pathnames.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-22


Symbolic Link: Files

ln - make symbolic links


• A symbolic link is a "file" pointing to another file.
• To make a symbolic link:
ln /original/file /new/link
• This makes /original/file and /new/link the same
file (edit one and the other will change).
• The file will not be gone until both /original/file
and /new/link are deleted.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-23


Symbolic Link: Directories (2)

• For folders, use a "soft" link.


ln -s /usr/src/linux-2.4.20 /usr/src/linux

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-24


File Systems (5)
• A directory in the Unix file system is just a
file with a list of all its children, so the
directories can be traversed with an iteration
scheme. One can sequentially iterate over
each child.
• If the normal command to print a file is
applied to a directory, the filenames in the
directory appear in the output (along with
other non-ASCII information).
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-25
File Systems (6)
• Suppose that we want to list the names of all
the files in a directory (including its
subdirectories), and in our output format files
of depth d have their names indented by d
tab characters.
• A short algorithm to do this task is given in
Figure 18.5. Output for the directory
presented in Figure 18.4 is shown in Figure
18.6.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-26
• The depth of a node in a tree is the length of
the path from the root to the node.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-27


Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-28
File Systems (7)
• The logic of the algorithm is simple to
follow. The current object is printed out,
with appropriate indentation.
• If the entry is a directory, process all the
children recursively, one by one.
• These children are one level deeper in the
tree and thus must be indented an extra tab
stop.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-29
Information on Blocks
• The numbers in parentheses in Figure 18.7
represent the number of disk blocks taken
up by each file. The directories themselves
are files, so they also use disk blocks.
• Suppose that we want to compute the total
number of blocks used by all files in our
example tree.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-30


Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-31
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-32
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-33
Binary Trees
• A binary tree has no node with more than
two children.
• Because there are only two children, name
them left and right.
• Recursively, a binary tree is either empty or
consists of a root, a left tree, and a right
tree.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-34


Binary Trees (2)
• One use of the binary tree is in the expression
tree, which is a central data structure in compiler
design.
• The leaves of an expression tree are operands,
such as constants or variable names; the other
nodes contain operators.
• This particular tree is binary because all the
operations are binary.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-35
Binary Trees (3)
import java.io.File;
public class FileSystem extends File{
public FileSystem ( String name ) {
super( name );
}
public void printName ( int depth ) {
for( int i = 0; i < depth; i++ )
System.out.print ( "\t" );
System.out.println ( getName( ) );
}
public void listAll( ) {
listAll( 0 );
}
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-36
Binary Trees (4)
private void listAll( int depth ){
printName ( depth );
if( isDirectory( ) ) {
String [ ] entries = list( );
for( int i = 0; i < entries.length; i++ ) {
FileSystem child = new FileSystem( getPath( )
+ separatorChar + entries[ i ] );
child.listAll( depth + 1 );
}
}
}
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-37
Binary Trees (5)
public long size( ) {
long totalSize = length( );
if( isDirectory( ) ) {
String [ ] entries = list( );
for( int i = 0; i < entries.length; i++ ) {
FileSystem child = new FileSystem( getPath( )+
separatorChar + entries[ i ] );
totalSize += child.size( );
}
}
return totalSize;
}
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-38
Binary Trees (6)
static public void main( String [ ] args ) {
FileSystem f;
if ( args.length == 0 )
f = new FileSystem( "." );
else
f = new FileSystem( args[ 0 ] );
f.listAll ( );
System.out.println( "Total bytes: " + f.size( ) );
}
}
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-39
Binary Trees (7)
• Although this case is the simplest, nodes
can have more than two children (and in the
case of unary operators, only one child).
• We can evaluate an expression tree T by
applying the operator at the root to the
values obtained by recursively evaluating
the left and right subtrees.
• Doing so yields the expression:
(a + ( (b-c) * d ) ).
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-40
Binary Trees (8)
• A second use of the binary tree is the
Huffman coding tree, which is used to
implement a simple but relatively effective
data compression algorithm.
• Each symbol in the alphabet is stored at a
leaf. Its code is obtained by following the
path to it from the root.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-41


Huffman Coding Tree

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-42


Binary Trees (9)
• Other uses of the binary tree are in binary
search trees which allow logarithmic time
insertions and accessing of items, and
priority queues, which support the access
and deletion of the minimum in a collection
of items.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-43


Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-44
Building a Tree
public Tree (Object cargo, Tree left, Tree right) {
        this.cargo = cargo;
        this.left = left;
        this.right = right;
}
Tree left = new Tree (new Integer (2), null, null);
Tree right = new Tree (new Integer(3), null, null);

Tree tree = new Tree (new Integer(1), left, right);

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-45


Class Integer

public final class Integer extends Number


implements Comparable
• Constructor
Integer (int value)
• Constructs a newly allocated Integer object
that represents the primitive int argument.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-46


Example
public class Tree {
Integer cargo;
Tree left;
Tree right;

Tree (Integer cargo, Tree left, Tree right) {


this.cargo = cargo;
this.left = left;
this.right = right;
}
}

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-47


Example (2)
public class treeDemo {
public static void print (Tree tree) { Output
if (tree == null)
return; 123
System.out.print (tree.cargo + " ");
print (tree.left);
print (tree.right);
}
public static void main (String args[]) {
Tree left = new Tree (new Integer (2), null, null);
Tree right = new Tree (new Integer(3), null, null);
Tree tree = new Tree (new Integer(1), left, right);
print (tree);
}
}
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-48
Traversing the Tree
• For example, a preorder tree traversal, work
at a node is performed before (pre) its
children are processed
• The traversal takes constant time per node.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-49


Preorder Traversal
• In a preorder traversal, the node is
processed and then its children are
processed recursively.
• The duplicate routine is an example of a
preorder traversal because the root is
created first.
• Then a left subtree is copied recursively,
followed by copying the right subtree.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-50


Preorder Traversal (2)

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-51


Preorder Traversal (3)
public static void print (Tree tree) {
        if (tree == null)
return;
        System.out.print (tree + " ");
        print (tree.left);
        print (tree.right);
}

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-52


Postorder Traversal
• In a postorder traversal, the node is
processed after both children are processed
recursively.
• Two examples are the methods size and
height. In both cases, information about a
node (e.g., its size or height) can be
obtained only after the corresponding
information is known for its children.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-53
Postorder Traversal (2)

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-54


Postorder Traversal (3)
public static void printPostorder (Tree tree){
        if (tree == null)
return;
        printPostorder (tree.left);
        printPostorder (tree.right);
        System.out.print (tree + " ");
}

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-55


Inorder Traversals
• To traverse a non-empty binary tree in
inorder, perform the following operations
recursively at each node:
– Traverse the left subtree.
– Visit the node.
– Traverse the right subtree.
• Also called Symmetric traversal.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-56


Traversals: Summary

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-57


printPostorder()

• Given a binary tree, print out the nodes of


the tree according to a bottom-up
"postorder" traversal.
• Both subtrees of a node are printed out
completely before the node itself is printed,
and each left subtree is printed before the
right subtree.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-58


printPostorder() (2)

• Produces the output "1 3 2 5 4".


• This is the sort of  bottom-up traversal that
would be used, for example, to evaluate an
expression tree where a node is an operation
like '+' and its subtrees are, recursively, the
two subexpressions for the '+'.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-59


Inorder Traversal
• In inorder traversal the left child is
recursively processed, the current node is
processed, and the right child is recursively
processed. This mechanism is used to
generate an algebraic expression
corresponding to an expression tree.
• For example, in Figure 18.11 the inorder
traversal yields (a+((b-c) *d)).
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-60
Inorder Traversal (2)

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-61


Inorder Traversal (3)
public static void printInorder (Tree tree) {
        if (tree == null)
return;
        printInorder (tree.left);
        System.out.print (tree + " ");
        printInorder (tree.right);
 }

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-62


Inorder Traversal (4)
• Produces the output "1 2 3 4 5". This is
known as an "inorder" traversal of the tree.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-63


Print Tree Rooted at Current Node
Using Preorder Traversal
public void printPreOrder( ) {
System.out.println (element);
if ( left != null )
left.printPreOrder ();
if ( right != null )
right.printPreOrder();
}
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-64
Print Tree Rooted at Current Node
Using Postorder Traversal (2)
public void printPostOrder( ) {
if ( left != null)
left.printPostOrder( );
if ( right != null )
right.printPostOrder( );
System.out.println (element);
}
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-65
Print Tree Rooted at Current Node
Using Inorder Traversal (3)
public void printInOrder( )
if (left != null)
left.printInOrder( );
System.out.println (element);
if (right != null)
right.printInOrder();
}
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-66
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-67
Postorder Traversal
and the Stack
• The postorder traversal is implemented by
using a stack to store the current state.
• The top of the stack will represent the node
that we are visiting at some instant in the
postorder traversal.
• However, we may be at one of three places
in the algorithm.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-68


Postorder Traversal
and the Stack (2)
1. About to make a recursive call to the
left subtree
2. About to make a recursive call to the
right subtree
3. About to process the current node

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-69


Postorder Traversal
and the Stack (3)
• Consequently, each node is placed on the
stack three times during the course of the
traversal.
• If a node is popped from the stack a third
time, we can mark it as the current node to
be visited.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-70


Postorder Traversal
and the Stack (4)
• Otherwise, the node is being popped for
either the first time or the second time.
• In this case, it is not yet ready to be visited,
so we push it back onto the stack and
simulate a recursive call.
• If the node was popped for a first time, we
need to push the left child (if it exists) onto
the stack.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-71
Postorder Traversal
and the Stack (5)
• Otherwise, the node was node is declared
popped for a second time, and we push the
right child (if it exists) onto the visited. The
other times, we simulate stack.
• In any event, we then pop the stack,
applying the same test.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-72


Postorder Traversal
and the Stack (6)
• Note that, when we pop the stack, we are
simulating the recursive call to the
appropriate child.
• If the child does not exist and thus was
never pushed onto the stack, when we pop
the stack we pop the original node again.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-73


Postorder Traversal
and the Stack (7)
• Eventually, either the process pops a node
for the third time or the stack empties. In
the latter case, we have iterated over the
entire tree.
• We initialize the algorithm by pushing a
reference to the root onto the stack.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-74


Quick Summary

• The stack contains nodes that we have


traversed but not yet completed.
• When a node is pushed onto the stack, the
counter is 1, 2, or 3 as follows:
– If we are about to process the node's left subtree
– If we are about to process the node's right
subtree
– If we are about to process the node itself

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-75


Postorder Traversal: Example

• Let us trace through the postorder traversal.


• Initialize the traversal by pushing root a
onto the stack.
• The first pop visits a. This is a's first pop, so
it is placed back on the stack, and we push
its left child, b, onto the stack. Next b is
popped. It is b's first pop, so it is placed
back on the stack.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-76


Postorder Traversal

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-77


Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-78
Example (2)
• Normally, b's left child would then be
pushed, but b has no left child, so nothing is
pushed.
• Thus the next pop reveals b for the second
time, b is placed back on the stack, and its
right child, d, is pushed onto the stack. The
next pop produces d for the first time, and d
is pushed back onto the stack.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-79


Example (3)
• No other push is performed because d has
no left child. Thus d is popped for the
second time and is pushed back, but as it
has no right child, nothing else is pushed.
• Therefore the next pop yields d for the third
time, and d is marked as a visited node.
• The next node popped is b, and as this pop
is b's third, it is marked visited.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-80


Example (4)
• Then a is popped for the second time, and it
is pushed back onto the stack along with its
right child, c.
• Next, c is popped for the first time, so it is
pushed back, along with its left child, e.
• Now e is popped, pushed, popped, pushed,
and finally popped for the third time
(typical for leaf nodes).

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-81


Example (5)
• Thus e is marked as a visited node. Next, c
is popped for the second time and is pushed
back onto the stack.
• However, it has no right child, so it is
immediately popped for the third time and
marked as visited.
• Finally, a is popped for the third time and
marked as visited.
• At this point, the stack is empty and the
postorder traversal terminates.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-82
Inorder Traversal
• The inorder traversal is the same as the
postorder traversal, except that a node is
declared visited after it is popped a second
time.
• Prior to returning, the iterator pushes the
right child (if it exists) onto the stack so that
the next call to advance can continue by
traversing the right child.

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-83


Inorder Traversal (2)

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-84


Preorder Traversal
• The preorder traversal is the same as the
inorder traversal, except that a nodepreorder is
the is declared visited after it has been popped
the first time.
• Prior to returning, the iterator pushes the right
child onto the stack and then pushes the left
child.
• We want the left child to be processed before
the right child, so we must push the right child
first and the left child second.
Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-85
Preorder Traversal (2)

Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 18-86

You might also like