Você está na página 1de 25

505

CONTENTS
17.1 EXPRESSION TREES
Building a Binary Expression Tree
17.2 ITERATIVE TREE TRAVERSAL
Inorder Iterative Traversal
Implementing the InorderIterator
Class
17.3 EULER TOUR TRAVERSAL
17.4 DRAWING A BINARY TREE
Building a Shadow Tree
Displaying a Shadow Tree
of a tree iterator is more complex than the implementa-
tion of an iterator used by structures that implement the
List interface. We will show how to construct an itera-
tor for a binary tree that implements an iterative inorder
scan of the tree nodes.
Section 17.3 develops the Euler tree traversal that
generalizes the basic recursive tree scanning algo-
rithms. The traversal defines a Euler tour which is used
to solve some interesting problems. In this chapter, we
use a Euler tour to fully parenthesize an expression
represented by a binary expression tree.
In Chapter 16, we introduced console and graphical
tree display methods. They produce an upright (vertical)
view of a tree. The algorithm that implements the dis-
play methods uses a variety of scanning techniques as
well as a modified version of the tree copy algorithm in
Chapter 16. It draws on many basic tree handling con-
cepts and is discussed as an application in Section 17.4.
Chapter 16 introduced binary trees. The focus was on
designing and implementing tree-handling algorithms.
In this chapter, we will use binary trees as a problem-
solving tool in a variety of applications. We will wait
until Chapter 18 to define a special type of binary tree
called a search tree. This collection type introduces a
whole new category of data structures.
Binary trees have important applications in lan-
guage parsing. An example is the construction of a
binary expression tree. This structure represents an
arithmetic expression in the form of a binary tree.
Recursive scans of an expression tree return the pre-
fix, infix, and postfix (RPN) form of the expression.
In earlier chapters, we studied iterators for
LinkedList and ArrayList collections. These ob-
jects provide sequential access to the elements. The
concept of an iterator extends to binary trees. Because a
binary tree is a nonlinear structure, the implementation
17.1 Expression Trees
A compiler uses a binary tree to represent an arithmetic
expression. The nodes of the tree, called an expression
tree, are binary operators and operands. We will now de-
velop an algorithm that shows you how to take an arith-
metic expression in postfix notation and create the
expression tree. You can refer back to Chapter 14 in
which we introduced infix and postfix notation for an
Chapter 17
BINARY TREE APPLICATIONS
arithmetic expression. These formats specify the posi-
tion of a binary operator and its operands. In postfix no-
tation, the binary operator comes after its operands, and
in infix notation, the operator appears between its
operands. A third notation, called prefix notation, places
a binary operator before its operands. The expressions in
Table 17.1 include each of the formats.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 505
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
506 Chapter 17 Binary Tree Applications
Table 17.1 Infix, postfix, and prefix notation.
Infix Postfix Prefix
a*b ab* *ab
a+b*c abc*+ +a*bc
a+b*c/de abc*d/+e +a/*bcde
The preorder and postorder traversals of a binary expression tree produce the prefix
and postfix notation for the expression. An inorder traversal generates the infix form of
the expression, assuming that parentheses are not needed to determine the order of evalu-
ation. For instance, in Figure 17.1c, the following are different traversals of the expression
a + b*c/de
Preorder (Prefix): + a / * b c d e // preorder scan
Inorder (Infix): a + b * c / d e // inorder scan
Postorder (Postfix): a b c * d / + e // postorder scan
In an expression
tree, each opera-
tor is an interior
node whose chil-
dren are operands
or subexpres-
sions. Operands
are in leaf nodes.
(a) a*b (b) a b* c (c) a b*c/d e
a
*
b
b
*
c
a

b
*
c
a

/
d

e
Figure 17.1 Binary expression trees.
An expression
tree represents
an arithmetic
expression.
Assume an arithmetic expression involves the binary operators addition subtrac-
tion multiplication , and division (/ ). In the expression tree, each operator has two
children that are either operands or subexpressions. A binary expression tree consists of
leaf nodes which contain a single operand
nonleaf nodes which contain a binary operator
the left and the right subtrees of an operator, describing a subexpression, which is
evaluated and used as one of the operands for the operator
The trees in Figure 17.1 describe the expressions in Table 17.1.
(*) (-),
(+),
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 506
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
top
a
Section 17.1 Expression Trees 507
Building a Binary Expression Tree
To build an expression tree, we need to develop an iterative algorithm that takes a string
containing an expression in postfix form. An operand is a single character such as a or
b. Our algorithm follows the steps of the postfix evaluation algorithm in Section 14.4. A
stack holds the operands, which in this case are trees. More specifically, the stack holds
TNode references that are the roots of subtree operands. In the postfix evaluation algo-
rithm, whenever we located an operator, we popped its two operands from the stack and
computed the result. In this algorithm, when we locate an operator, we construct a subtree
and insert its root reference onto a stack. The following is a description of the action taken
when we encounter an operand or an operator in the input string.
If the token is an operand, we use its value to create a leaf node whose left and right
subtrees are null. The leaf node is pushed onto a stack of TNode references.
If the token is an operator, we create a new node with the operator as its value. Be-
cause the operator is binary, it must have two children in the tree. The children hold
the operands for the operator. A child may be a single operand (leaf node) or a
subexpression represented by a subtree with an operator as the root. The child
nodes are on the stack from a previous step. Pop the two child nodes from the stack
and attach them to the new node. The first child popped from the stack becomes the
right subtree of the new node and the second child popped from the stack becomes
the left subtree.
The method buildExpTree() implements the algorithm. The following steps illus-
trate the action of the method for the expression in postfix form. We represent the
stack horizontally to simplify the view of the elements. Remember, each element is a sub-
tree specified by its root.
a b c * +
Step 1: Recognize a as an operand. Construct a leaf node containing the Character
value a and push its reference onto the stack s.
a + b * c
Step 4: Recognize as an operator. Create a new node with as its value. Then
pop two subtrees (node c and node b ) from the stack. These are the right
* *
a b
top
c
Steps 23: Recognize b and c as operands, construct leaf nodes, and push their ref-
erences onto the stack.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 507
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
508 Chapter 17 Binary Tree Applications
and left subtrees of the new node respectively. Attach the subtrees and push
the new subtree (root ) on the stack. *
Step 5: Recognize as an operator. Create a new node with as its value. Pop
its two operands from the stack, attach them to the node, and push the new
subtree (root ) on the stack. +
+ +
Step 6: We have reached the end of the expression. The single item on the stack is
the root of the expression tree.
The method buildExpTree() applies this algorithm to construct the expression
tree for a correctly formed postfix expression. The method performs no error checking. It
assumes that an operand is a single character and that the available operators are
and /. In addition, the expression can contain the whitespace characters blank or tab.
buildExpTree():
public static TNode<Character> buildExpTree(String postfixExp)
{
// newNode is a reference to the root of subtrees we build,
// and newLeft/newRight its are its children
TNode<Character> newNode, newLeft, newRight;
char token;
// subtrees go into and off the stack
ALStack<TNode<Character>> s =
new ALStack<TNode<Character>>();
int i = 0, n = postfixExp.length();
+, -, *,
Build an expres-
sion tree from the
postfix input by
modifying the
postfix expression
evaluation
algorithm from
Chapter 14.
top
b a
*
c
top
b
*
c
a

FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 508


PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Section 17.1 Expression Trees 509
// loop until i reaches the end of the string
while(i != n)
{
// skip blanks and tabs in the expression
while (postfixExp.charAt(i) == ' ' ||
postfixExp.charAt(i) == '\t')
i++;
// if the expression has trailing whitespace, we could
// be at the end of the string
if (i == n)
break;
// extract the current token and increment i
token = postfixExp.charAt(i);
i++;
// see if the token is an operator or an operand
if (token == '+' || token == '-' ||
token == '*' || token == '/')
{
// current token is an operator; pop two subtrees off
// the stack
newRight = s.pop();
newLeft = s.pop();
// create a new subtree with token as root and subtrees
// newLeft and newRight and push it onto the stack
newNode =
new TNode<Character>(token,newLeft,newRight);
s.push(newNode);
}
else // must be an operand
{
// create a leaf node and push it onto the stack
newNode = new TNode<Character>(token);
s.push(newNode);
}
}
// if the expression was not empty, the root of
// the expression tree is on the top of the stack
if (!s.isEmpty())
return s.pop();
else
return null;
}
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 509
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
510 Chapter 17 Binary Tree Applications
PROGRAM 17.1 BUILDING EXPRESSION TREES
This program is a GUI application that illustrates buildExpTree(). The window contains
a text field, called expInput, in the north region and a text area, called expTree, at the
center. An action event on the text field registers an ExpressionHandler object as the lis-
tener. The inner class implements actionPerformed(). A user enters a correctly formed
postfix expression in the text field and presses the Enter key. The event handler displays the
expression in the text area and then calls buildExpTree() to construct the corresponding
binary expression tree. The handler then uses displayTree() to view the tree in the text
area. It concludes by displaying the preorder, inorder, and postorder scans of the tree.
The application clears the text field so that a user may conveniently enter a series of
expressions and maintain a history of the output in a scrollable text area. Figure 17.2 is a
snapshot of program execution after the user enters the expression
a b c * de / + // Infix form: a + (b*cd)/e
Note that the postorder and preorder scans correspond to the postfix and prefix versions of the
expression, but the infix scan does not reflect the parentheses in the original infix expression.
The following is the source code for actionPerformed() that handles the event
caused when the user presses the Enter key.
public void actionPerformed(ActionEvent ae)
{
// obtain the expression the user typed
String expression = expInput.getText();
// build the expression tree
TNode<Character> root = BinaryTree.buildExpTree(expression);
// output the expression and its tree
textArea.append("Expression tree for " +
expression + "\n\n");
textArea.append(BinaryTree.displayTree(root, 1) + "\n");
// output the scans
Figure 17.2 Run of Program 17.1.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 510
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Section 17.2 Iterative Tree Traversal 511
textArea.append("Preorder scan: " +
BinaryTree.preorderDisplay(root) + "\n\n");
textArea.append("Inorder scan: " +
BinaryTree.inorderDisplay(root) + "\n\n");
textArea.append("Postorder scan: " +
BinaryTree.postorderDisplay(root) + "\n\n");
// clear the text field
expInput.setText("");
}
17.2 Iterative Tree Traversal
A tree iterator
scans the ele-
ments as if the
tree were linear.
We have observed the power of iterators to scan the elements in a LinkedList or
ArrayList collection. Traversing the nodes in a binary tree is more difficult because a tree
is a nonlinear structure and there is no one traversal order. Section 16.3 discusses recursive
algorithms for performing a preorder, inorder, and postorder scan in a tree. The problem with
each of these traversal algorithms is that there is no escape from the recursive process until it
completes. We cannot easily stop the scan, examine the contents of a node, and then contin-
ue the scan at another node in the tree. We need an iterative process to implement a binary
tree iterator. One choice would be a level-order scan using a queue. As we will discover with
binary search trees, an iterative version of a recursive scan is a better choice.
In this section, we will implement an iterator using an iterative inorder scan. Creating
iterators with a preorder and a postorder iterative scan are left for the exercises. You are fa-
miliar with iterators and the Iterator interface from our discussion of the LinkedList
class. Our binary tree iterator implements this interface. To provide an iterative scan of the
elements, we use a stack to hold the nodes that have been visited. In this way, we can sim-
ulate the runtime system, which uses a stack to hold the recursive calls that are made dur-
ing an inorder recursive scan of the tree. Because it is our stack, we can halt at any time,
access a node, and then continue by popping the stack to pick up the scan. Figure 17.3
InorderIterator
hasNext(): boolean
next(): T
remove(): void
InorderIterator(root:TNodeT)
goFarLeft(t:TNodeT): TNodeT
hasNext(): boolean
next(): T
remove(): void
s: ALStackTNodeT null
curr:TNodeT null
interface
Iterator
T
T
Figure 17.3 InorderIterator
implements the Iterator interface.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 511
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
512 Chapter 17 Binary Tree Applications
gives a UML diagram for the class InorderIterator. The diagram includes the instance
variables and the private method goFarLeft(), which is critical to finding the next node.
Inorder Iterative Traversal
The inorder iterative traversal emulates a recursive scan. Use of a stack is a key feature. Nodes
enter the stack when we move down the tree from the current iterator (node) position to the
node that references the next iterator position. In this way, the iterative algorithm can re-
member each intermediate node on the path so it can come back up the tree and visit the node
at a later point. To do this, push on a stack the references to each of the nodes that are discov-
ered on the path to the next element.
An iterative scan begins at the leftmost node in the tree. The starting point is found by
starting at the root and following the chain of left children until we locate a node with an
empty left subtree. An iterator initially references this node. The root and all intermediate
nodes on the path of left children are pushed on the stack.
The iterative traversal of the tree is based on the following set of rules.
1. At each node, capture the value of the node.
2. If the right branch of the node is not empty, move to the right child and then traverse
the path of left children until we locate a node with a null left subtree. The traversal
identifies this node as the next node. Push on the stack a reference to the right child
and each intermediate node on the path.
3. If the right branch of the node is empty, we have completed the scan of the nodes left
branch, the node itself, and its right branch. The next node to visit is on the stack. If
the stack is not empty, pop it to determine the next node in the scan. If the stack is
empty, all nodes have been visited and we terminate the scan.
Let us trace the iterative inorder traversal of nodes in the following character tree. The
order of visits to the nodes is B F D A E C. We organize the trace around the order in which
nodes are scanned. In this way, you can understand how the algorithm uses the stack and
the traversal rules to proceed from a current scan position to the next scan position.
Scan B and then F:
The iterator is initially positioned at node B. We arrive there by starting at the
root and traversing the path of left children. The one node on this path, namely
the root A, is placed on the stack (a). By rule 2, the next element is node F, which
is the leftmost node in the right subtree of B. The path to F encounters node D
which is pushed on the stack (b).
Inorder iterative
tree traversal is
implemented by
using a stack to
simulate the
recursion.
Visit B
Visit F
(a) Begin iteration at the leftmost node
Push node A on the stack
(b) Move from B to F using Rule 2
Push node D on the stack
A
Stack
B
D E
A
C
F
A
A D
Stack
B
D E
C
F
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 512
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Section 17.2 Iterative Tree Traversal 513
Scan D and then A:
Node F has no right child. By rule 3, the next node is D, which is popped from
the stack (c). The same rule 3 applies to D. The next node is A (d).
Visit D
A
Stack
B
D E
C
F
A
Stack
B
D E
Visit A
C
F
A
(c) By rule 3, the node is D
Pop D from the stack
By rule 3, the node is A
Pop A from the stack
(d)
Scan E then C:
From node A, use rule 2 to visit the next node E. Node C is on the path from A to
E and thus is pushed on the stack (e). By rule 3, the next node C, which is popped
from the stack (f).
Visit E
Visit C
(e) By rule 2, the next node is E
Push C on the stack
(f ) By rule 3, the next node is C
Pop C from the stack
C
Stack
B
D E
C
F
Stack
B
D E
C
F
A A
At node C, rule 3 applies. The stack is empty, and the scan is complete.
Implementing the InorderIterator Class
The InorderIterator class provides instances that execute an iterative inorder scan
of a binary tree. The class implements the Iterator interface. However, the
remove() method is defined but does not carry out any operation. Its use throws the
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 513
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
514 Chapter 17 Binary Tree Applications
UnsupportedOperationException. In reality, an InorderIterator object is de-
signed to scan a binary tree and simply access the value of the elements. The private
data members include a stack of TNode references and the variable curr, which is the
next node we visit in the inorder traversal. The end of a traversal occurs when curr be-
comes null. The method hasNext() simply checks if curr is not null.
InorderIterator class:
public class InorderIterator<T> implements Iterator<T>
{
private ALStack<TNode<T>> s = null;
private TNode<T> curr = null;
. . .
}
The class uses the private method goFarLeft() to locate the first element and to ex-
ecute rule 2. The method begins at node t and stacks all of the nodes until it locates one
with a null left subtree. A reference to this node is the return value.
goFarLeft():
// go far left from t, pushing all the nodes with
// left children on stack s
private TNode<T> goFarLeft(TNode<T> t)
{
if (t == null)
return null;
while (t.left != null)
{
s.push(t);
t = t.left;
}
return t;
}
The constructor allocates the stack and calls goFarLeft() to position curr at the
first node inorder. Because InorderIterator is not included in a collection class, the
user must create an instance using the operator new and pass the root of the binary tree as
an argument.
Constructor:
public InorderIterator(TNode<T> root)
{
s = new ALStack<TNode<T>>();
curr = goFarLeft(root);
}
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 514
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Section 17.2 Iterative Tree Traversal 515
The method next() implements Steps 1 through 3. In keeping with the require-
ments of the Iterator interface, next() throws NoSuchElementException if the
tree traversal is complete.
next():
public T next()
{
if (curr == null)
throw new NoSuchElementException(
"InorderScan: no elements remaining");
// capture the value in the node
T returnValue = curr.nodeValue;
if (curr.right != null) // have a right subtree
// stack nodes on left subtree
curr = goFarLeft(curr.right);
else if (!s.isEmpty())
// no right subtree; there are other nodes
// to visit; pop the stack
curr = (TNode<T>)s.pop();
else
curr = null; // end of tree; set curr to null
return returnValue;
}
PROGRAM 17.2 ITERATIVE TREE TRAVERSAL
For the purpose of demonstrating InorderIterator, we will use the static method
buildTime24Tree() in the BinaryTree class. The method builds the following binary
tree of Time24 objects.
10:45
15:30 12:00
3:15
9:15
18:35
7:30
20:55
5:15
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 515
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
516 Chapter 17 Binary Tree Applications
The program calls buildTime24Tree() to create the tree, and then uses an inorder
tree iterator to traverse the nodes. After each call to next(), the program updates the time
value of the node by adding 60 minutes (1 hour). A call to displayTree() outputs the
updated tree.
import ds.util.TNode;
import ds.util.BinaryTree;
import ds.util.InorderIterator;
import ds.time.Time24;
public class Program17_2
{
public static void main(String[] args)
{
// roots for the tree
TNode<Time24> root;
// build a tree of Time24 data
root = BinaryTree.buildTime24Tree();
// display the tree
System.out.println("Original tree");
System.out.println(BinaryTree.displayTree(root, 5) +
"\n");
// declare an inorder tree iterator
InorderIterator<Time24> iter =
new InorderIterator<Time24>(root);
// go through the tree and add 1 hour to each time
while (iter.hasNext())
{
// obtain the value in a tree node
Time24 t = iter.next();
// add 1 hour to the time
t.addTime(60);
}
System.out.println("Modified tree");
System.out.println(BinaryTree.displayTree(root, 5));
// delete the nodes in the tree
BinaryTree.clearTree(root);
}
}
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 516
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Section 17.3 Euler Tour Traversal 517
17.3 Euler Tour Traversal
Up to this point, all of our tree traversal algorithms visit each node exactly once. For in-
stance, the inorder traversal visits the node between visiting the left subtree and the right
subtree. We need a more general tree traversal algorithm for some applications, one that
will visit each node more than once. The Euler tour traversal provides a solution. We as-
sume that the edges and nodes of a tree T are contained in a walkway with walls on both
sides. The Euler tour is a walk around T, touching each node as we encounter it, always
keeping the wall on our right. The tour visits each node three times:
on the left, before the Euler tour of the nodes left subtree
from below, as we finish the tour of the left subtree
on the right, after we finish the Euler tour of the right subtree
If the node is a leaf, all of the visits are combined into a single visit. The walk in
Figure 17.4 traverses an expression tree. The directed edges trace the Euler tour beginning
with the root. We encounter nodes in the following order:
Tour visits: + * a * d e * + / b / c / +
Run:
Original tree
3:15
18:35 20:55
10:45 12:00 15:30
5:15 7:30 9:15
Modified tree
4:15
19:35 21:55
11:45 13:00 16:30
6:15 8:30 10:15
*
a
d e
b c

/
Figure 17.4 Euler tour of an expression tree.
The following pseudo-code description of the algorithm summarizes the Euler tour.
A single visit to a leaf node and multiple visits to a nonleaf node are simply denoted by
visit although, in practice, an implementation does not perform the same action.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 517
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
518 Chapter 17 Binary Tree Applications
Algorithm eulerTour(TNode t):
if t null
if t is a leaf node
visit t
else
visit t // on the left
eulerTour(t.left);
visit t; // from below
eulerTour(t.right);
visit t; // on the right
The recursive algorithm allows us to pause three times to perform a visit. You should
note that the Euler tour generalizes the inorder, postorder, and preorder tree traversals. For
instance, if the visit on the left and the visit on the right do nothing, the Euler tour is equiv-
alent to an inorder traversal.
An expression tree provides a good application of a Euler tour. The traversal includes
visits that add parentheses and that access the value of a node. The result is a string that
represents an equivalent fully parenthesized expression. The algorithm is straightforward.
A visit to a leaf node (operand) inserts the operand in the string. For a nonleaf node (op-
erator), insert a ( as the visit on the left, insert the operator as the visit from below, and
insert a ) as the visit on the right. The static method fullParen() in the BinaryTree
class implements the algorithm.
fullParen():
// traverse an expression tree and display the equivalent
// fully parenthesized expression
public static <T> String fullParen(TNode<Character> t)
{
String s = "";
if (t != null)
{
if (t.left == null && t.right == null)
s += t.nodeValue; // visit a leaf node
else
{
s += "("; // visit on left
s += fullParen(t.left);
s += t.nodeValue; // visit from below
s += fullParen(t.right);
s += ")"; // visit on right
}
}
return s;
}
The Euler tour
generalizes the
recursive tree
traversals by
allowing three
visits to a node.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 518
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Section 17.3 Euler Tour Traversal 519
Run:
Enter a postfix expression: a d e * b c / +
Expression tree
+
* /
a b c
d e
Fully parenthesized expression: ((a*(d-e))+(b/c))
PROGRAM 17.3 EULER TOUR TRAVERSAL
The program prompts for an RPN expression and constructs an expression tree by calling the
method buildExpTree() from the BinaryTree class. After displaying the tree using
displayTree(), the program calls fullParen() and outputs the equivalent fully paren-
thesized expression. The run constructs the expression tree in Figure 17.4.
import java.util.Scanner;
import ds.util.TNode;
import ds.util.BinaryTree;
public class Program17_3
{
public static void main(String[] args)
{
// prompt for the RPN expression
Scanner keyIn = new Scanner(System.in);
String postfixExp;
// root of the expression tree
TNode<Character> root;
System.out.print("Enter a postfix expression: ");
postfixExp = keyIn.nextLine();
// build the expression tree
root = BinaryTree.buildExpTree(postfixExp);
// display the tree
System.out.println("Expression tree");
System.out.println(BinaryTree.displayTree(root,1));
// output the full parenthesized expression
System.out.print("Fully parenthesized expression: ");
System.out.println(BinaryTree.fullParen(root));
}
}
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 519
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
520 Chapter 17 Binary Tree Applications
17.4 Drawing a Binary Tree
In Chapter 16, we introduced the methods displayTree(), drawTree(), and drawTrees().
These methods implement algorithms that employ many of the basic features of a binary
tree. Let us look at the design of the console-based displayTree() method. The graphi-
cal methods use the same design. Their implementation differs only when inserting a node.
The graphical methods draw a circle, text for the value, and edges to the nonnull children.
View the display of the tree as a rectangular grid with a cell denoted by the pair (level,
column). The level is a row in the grid corresponding to a level in the tree. The column co-
ordinate designates a region of the display measured left to right. Figure 17.5 is the repre-
sentation of Tree 0 in the grid. The algorithm to display a tree uses a recursive scan to
create a copy of the original tree. The copy is called a shadow tree. The nodes of the shad-
ow tree store the value of the node in the original tree formatted as a string and the (level,
col) position of the shadow tree node in the grid. A level-order scan of the shadow tree dis-
plays the nodes.
The binary tree-
drawing algorithm
first constructs a
shadow tree using
an inorder scan.
Each node in the
shadow tree
defines its column
in the grid.
Building a Shadow Tree
The recursive function buildShadowTree() uses an inorder scan (LNR) of the original
tree to build a shadow tree. As the inorder scan progresses, we move from one grid column
to another. For instance, with Tree 0, the order of visits is B D A E C. Note in Figure 17.5
that this is the column-order for the nodes in the tree.
A shadow tree uses an augmented node structure for its elements. The TNodeShadow
objects have the basic TNode structure, with additional variables level and column that
specify the coordinates for a cell in the grid. The variable nodeValueStr is a string that
describes the value for a node in the original tree. For instance, if a tree node has integer
value 135, then nodeValueStr in the corresponding shadow tree is 135.
A shadow tree
maintains the
node value as a
string and the
level (row) and
column of the
node.
level 0
level 2
level 1
col
2
col
3
col
4
col
0
col
1
A
B C
D E
A
B
D
C
E
Figure 17.5 Square grid containing nodes denoted by the pair
(level, col).
left nodeValueStr level column right
TNodeShadow object
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 520
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Section 17.4 Drawing a Binary Tree 521
TNodeShadow class:
class TNodeShadow
{
public static int columnValue;
public String nodeValueStr; // formatted node value
public int level, column;
public TNodeShadow left, right;
public TNodeShadow ()
{}
}
The algorithm for buildShadowTree() resembles copyTree() with the exception
that it makes an inorder scan of the original tree rather than a postorder scan. Each recursive
call allocates a TNodeShadow object and assigns it the string that corresponds to the value of
the node in the original tree. It then makes recursive calls that create the left and right subtrees.
You will notice that the TNodeShadow class has a static variable columnValue. This variable
is key to the algorithm. Because the variable is static, it is global to the recursive process. Each
recursive call in the inorder scan creates a node in the column specified by columnValue and
then increments the variable for the subsequent recursive call. In this way, columnValue is
incremented on each visit to a node. If the tree has n nodes, columnValue has values ranging
from 0 for the first visit (leftmost node) to for a visit to the rightmost node. The
buildShadowTree() method has two parameters. The TNode reference t provides access to
the value of the original tree node. An integer denotes the level in the tree.
buildShadowTree():
// build a shadow tree that is used for tree display
private static <T> TNodeShadow buildShadowTree(TNode<T> t,
int level)
{
// new shadow tree node
TNodeShadow newNode = null;
String str;
if (t != null)
{
// create the new shadow tree node
newNode = new TNodeShadow();
// allocate node for left child at next level in tree;
// then attach the node
TNodeShadow newLeft = buildShadowTree(t.left, level+1);
newNode.left = newLeft;
// initialize instance variables in the new node
str = (t.nodeValue).toString(); // format conversion
newNode.nodeValueStr = str;
newNode.level = level;
newNode.column = TNodeShadow.columnValue;
n - l
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 521
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
522 Chapter 17 Binary Tree Applications
// update column to next cell in the table
TNodeShadow.columnValue++;
// allocate node for right child at next level in tree;
// then attach the node
TNodeShadow newRight = buildShadowTreeD(t.right, level+1);
newNode.right = newRight;
}
return newNode;
}
Displaying a Shadow Tree
The method displayTree() takes the root, t, of the binary tree as an argument and calls
buildShadowTree() to create a shadow tree.
// build the shadow tree
TNodeShadow shadowRoot = buildShadowTree(t, 0);
The algorithm displays the tree using a level-order scan of shadow tree nodes. Each
shadow tree node provides the node value as a string and the (level, column) coordinate for
an element. The scan uses a queue of TNodeShadow objects to store and access the nodes.
As shadow tree nodes emerge from the queue the displayTree() method positions the
value at (level, col) in the grid. To determine the location of each node in the grid, we use
the argument maxCharacters, which is the number of characters in the longest node
value. The variable colWidth, with value maxCharacters + 1, defines the width of
each cell in the display (Figure 17.6). The variable currLevel is the current level during
the scan and the variable currCol is the current column coordinate in the grid. The string
representation of the tree is stored in the variable displayStr.
Cell (level, col) (2,1)
Indent 3*colWidth spaces
from last node output.
level 0
level 2
level 1
col
2
col
3
col
4
col
0
col
1
A
B C
D E
Figure 17.6 Displaying a node value on the current line.
// use for the level-order scan of the shadow tree
LinkedQueue<TnodeShadow> q =
new LinkedQueue<TnodeShadow>();
String displayStr = "";
int colWidth = maxCharacters + 1;
int currLevel = 0, currCol = 0;
// use during the level-order scan of the shadow tree
TNodeShadow currNode;
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 522
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Section 17.4 Drawing a Binary Tree 523
As nodes are popped from the queue into the reference variable currNode, display
Tree() carries out the task of displaying the node value (currNode.nodeValueStr) at
the grid coordinates (currNode.level, currNode.column). The column position com-
bines with the value of colWidth to specify how far we must move to the right before in-
serting the node. Because the level-order scan visits siblings from left to right, the distance
of the move is determined by comparing the column positions for successive siblings. The
variable currLevel maintains a record of the current level (line) on which nodes are dis-
played. The value of currLevel is incremented whenever a node is popped from the
queue with a level greater than colLevel. The implementation simply inserts a newline
character to move down one level. The string continues to add node values on the same
level until another change is required. The private methods formatString() and
formatChar() output a string and a character right-justified in a specified number of
print positions. They are used to position the tree nodes in their proper columns. The doc-
umentation comments in the code listing allow you to understand the remaining details of
the method implementation.
displayTree():
// return a string that displays a binary tree; output of
// a node value requires no more than maxCharacters
public static <T> String displayTree(TNode<T> t, int
maxCharacters)
{
// use for the level-order scan of the shadow tree
LinkedQueue<TNodeShadow> q =
new LinkedQueue<TNodeShadow>();
String displayStr = "";
int colWidth = maxCharacters + 1;
int currLevel = 0, currCol = 0;
TNodeShadow.columnValue = 0;
if (t == null)
return displayStr;
// build the shadow tree
TNodeShadow shadowRoot = buildShadowTree(t, 0);
// use during the level order scan of the shadow tree
TNodeShadow currNode;
// insert the root in the queue and set current level to 0
q.push(shadowRoot);
// continue the iterative process until the queue is empty
while(!q.isEmpty())
{
// delete front node from queue and make it the current
// node
currNode = q.pop();
Display the tree
with a level-order
scan of the shad-
ow tree. The scan
uses the node
data to position
and display each
node.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 523
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
524 Chapter 17 Binary Tree Applications
// if level changes, output a newline
if (currNode.level > currLevel)
{
currLevel = currNode.level;
currCol = 0;
displayStr += '\n';
}
// if a left child exists, insert the child in the queue
if(currNode.left != null)
q.push(currNode.left);
// if a right child exists, insert the child in the queue
if(currNode.right != null)
q.push(currNode.right);
// output formatted node value
if (currNode.column > currCol)
{
displayStr +=
formatChar((currNode.column-currCol) * colWidth,
' ');
currCol = currNode.column;
}
displayStr += formatString(colWidth,
currNode.nodeValueStr);
currCol++;
}
displayStr += '\n';
// delete the shadow tree
shadowRoot = clearShadowTree(shadowRoot);
return displayStr;
}
Chapter Summary
In a binary expression tree, each operand is located in a leaf node, and each operator is
in an interior node. The two children of an operator are either an operand or a subex-
pression. The method buildExpTree() takes a string argument specifying a postfix ex-
pression and builds the corresponding expression tree. The algorithm is very similar to
the one that evaluates a postfix expression in Section 14.4; however, in buildExpTree(),
the stack maintains subtrees of the final expression tree rather than arithmetic values.
A recursive tree scan algorithm such as LNR (inorder) does not allow escape from the re-
cursion. The programmer cannot leave the method, perform some action, and return
later to continue the traversal. Hence, an iterative tree traversal is often useful. We saw an
example of iterative traversal when we studied the LinkedList iterator in Chapter 12. The
InorderIterator class implements the Iterator interface and uses a stack to implement an it-
erative traversal of a binary tree. Essentially, the stack simulates the recursion.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 524
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Programming Exercises 525
Written Exercises
1. Write the infix expression
in postfix and prefix form and draw an expression tree for it.
2. Explain why an inorder scan of an expression tree may not be the infix form of the ex-
pression. Give an example to illustrate your argument.
3. Why is developing an iterator for a binary tree a more difficult problem than develop-
ing an iterator for a linked list?
4. Explain why the Euler tour is more general than any of the preorder, inorder, and
postorder scanning algorithms.
5. Explain the role of the shadow tree in the algorithm used by displayTree().
a + 2 * b
(c + d)
+ 8 * e
The Euler tour traversal generalizes the recursive tree scanning algorithms and allows
the visit of a node three times during a tree traversal. A Euler tour can traverse an ex-
pression tree and display the equivalent fully parenthesized expression.
The displayTree() method of the BinaryTree class first constructs a shadow tree by
performing an inorder traversal of the original binary tree. The shadow tree nodes con-
tain the data of the original tree node formatted as a string along with data that speci-
fy the position of the node in tree display. A subsequent level-order scan outputs the
tree display.
Programming Exercises
6. Implement a method treeSize() that uses an inorder iterator to traverse a binary
tree and returns the number of nodes in the tree. In your program, create Tree 0,
Tree 1, and Tree 2 using the method buildTree() in the class BinaryTree. Using
treeSize(), output the number of nodes in each tree.
public static <T> int treeSize(TNode<T> t)
{ ... }
7. (a) Implement the method find() that iteratively traverses a binary tree, searches
for a specified node value, and returns a reference to a node containing the value
or null if the value is not in the tree.
public static <T> TNode<T> find(TNode<T> t, T item)
{ ... }
(b) In a program, create and display Tree 2 using buildTree() and display
Tree() in the class BinaryTree. Prompt the user to input a value in the range
A to I. Call find() to locate the node, N, in Tree 2 that matches the input
value. Output the left and right children of N.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 525
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
526 Chapter 17 Binary Tree Applications
8. (a) Implement a method buildCTree() that takes an ArrayList parameter and
builds a complete tree from its elements. A level-order scan of the tree returns the
original ArrayList elements. Implement your algorithm by using a queue to
hold TNode references in a fashion similar to the level-order scanning algorithm
from Chapter 16.
public static <T> TNode<T> buildCTree(ArrayList<T> alist)
{ ... }
For instance, if buildCTree() should construct the com-
plete tree.
alist = 51, 2, 3, 4, 56,
1
2
4 5
3
6
(b) Implement method buildCIntTree() that constructs a complete tree containing
the values
public static TNode<Integer> buildCIntTree(int n)
{ ... }
(c) Implement method buildCCharTree() that constructs a complete tree contain-
ing the characters from a specified string.
public static TNode<Character> buildCCharTree(String
str)
{ ... }
(d) In the program, build complete trees containing the integer values from 1 to 10 and
the characters in the string generics. Using the method drawTrees() in the
class BinaryTree, graphically display the integer tree. Then, using drawTree()
in the same class, draw the character tree.
9. (a) As we will see in Chapter 18, it is often useful for a tree node to contain a refer-
ence to its parent. Using the parent reference, it is possible to begin at a specified
node and follow the parent references all the way to the root node. Implement the
class TNodeP that adds the parent reference.
public class TNodeP<T>
{
// node's value
public T nodeValue;
51, 2, 3, , n6.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 526
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Programming Exercises 527
// subtree references
public TNodeP<T> left, parent, right;
// create instance with a value, null subtrees, and
// null parent
public TNodeP(T item)
{ ... }
// initialize the value, the subtrees, and the parent
public TNodeP (T item, TNodeP<T> parent,
TNodeP<T> left, TNodeP<T> right)
{ ... }
}
(b) Chapter 16 developed an algorithm that uses a postorder scan of a binary tree in
order to produce a copy of the tree. Implement a method copyTreeP() that takes
the root of a binary tree and creates a copy whose nodes include parent references
(TNodeP objects).
// create a TNodeP duplicate of the tree with root t and
// return a reference to its root
public static <T> TNodeP<T> copyTreeP(TNode<T> t)
{ ... }
(c) In a program, build Tree 1 using the method buildTree(). Apply copyTreeP()
to make a copy that includes parent references. Starting at the root of the new tree,
follow the path of right subtrees until encountering node N with a null right sub-
tree. Beginning with node N, output the path of nodes from N up to the root.
10. Modify the buildExpTree() method so it constructs the binary expression tree from
a string containing an expression in prefix format. Modify Program 17.1 so it uses
your method.
11. Implement a method evalExpTree() that traverses an expression tree whose operands
are single-digit integers and evaluates the expression. In your program, input a post-
fix expression from the keyboard, call evalExpTree(), and output the value of the
expression.
12. Do Programming Exercise 17.11, but test evalExpTree() in a GUI program. The pro-
gram should output the expression tree and the value of the expression in a text area.
13. (a) Develop a class, PreorderIterator, that implements the Iterator interface
and performs an iterative preorder traversal of a binary tree. The iterator should
visit each node, followed by a visit of the left subtree and then the right subtree.
Like the class InorderIterator of Section 17.2, use a stack to hold node ref-
erences. Suppose we are at node A of a binary tree and execute the visit. We must
next visit the left subtree of A and come back at a later point to visit the right
subtree of A. If the right subtree is not empty, use a stack to store the reference to
the right subtree. After visiting all of the nodes on the left subtree of A, pop the
stack and return to scan the right subtree. We show these two situations in the
following figure.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 527
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
528 Chapter 17 Binary Tree Applications
The iterative scan algorithm uses the following steps. Start with the root node.
If the root node is null, the tree is empty and the iteration is complete.
For each node in the tree,
(1) capture the value stored in the node.
(2) if the right subtree is nonnull, save the right child reference in a stack.
(3) if the left child is nonnull,
set the current node to be the left child
else if the stack is not empty,
pop the stack and assign the return value as the current node
else
traversal is complete.
(b) Write a program that creates Tree 0, Tree 1, and Tree 2. Using PreorderIterator,
output the preorder traversal for each tree.
14. This exercise considers the problem of computing the number of descendants of each
node in a binary tree. For instance, in the figure we annotate each node of Tree 1 with
its number of descendants.
top
Push C
Visit A. Go left.
Pop C
top
Pop the stack and visit C
...
... C
A
B C
D
A
B C
D
D
#3 B
#8
Tree 1
#0
A
#3 C
#1 E
#0 G #0 H
#2 F
#0 J
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 528
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.
Programming Project 529
To determine the number of descendants of each node in a binary tree, initialize
an integer variable count to 0 and execute a Euler tour of a binary tree. When first
encountering a node on the left, increment count (add the node to the total node
count). When returning to the node on the right, the number of descendants is the dif-
ference between the current value of the variable and the value when the node was first
counted. Implement the strategy in an application that outputs the number of descen-
dants for each node in Tree 1.
Programming Project
15. (a) Develop a class, PostorderIterator, that implements the Iterator interface
and performs an iterative postorder traversal of a binary tree. The problem is more
difficult than an inorder or preorder traversal because we must distinguish be-
tween moving down the left branch of a node (state 0) or moving up the tree to a
node (state 1). When moving up the tree, there are two possible actions: visit the
right branch of a node or visit the node. Maintain the integer variable state. If
motion is down the tree. If motion is up. When coming
up the tree, the parent of the current node is on top of the stack. To determine if
we are coming from the left, compare the node reference to the parents left child.
If they agree and the parent has a right subtree, go down the subtree; otherwise,
visit the node and continue up the tree.
state = = 1, state = = 0,
Traverse left branch Traverse right branch
Visit and move up the tree
A
B C
(b) Write a program that creates Tree 0, Tree 1, and Tree 2. Using PostorderIterator,
output the postorder traversal for each tree.
FORDMC17_0130477249v3.qxd 11/12/04 5:05 PM Page 529
PRELIMINARY PROOFS
2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material is protected under all copyright laws as they currently exist.
No portion of this material may be reproduced, in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book: Data Structures with Java
by William Ford and William Topp: ISBN 0-13-046165-2.

Você também pode gostar