Professional Documents
Culture Documents
Binnary Tree Appliications
Binnary Tree Appliications
qxd
11/12/04
5:05 PM
Page 505
Chapter 17
BINARY TREE APPLICATIONS
CONTENTS
17.3 EULER TOUR TRAVERSAL
17.4 DRAWING A BINARY TREE
of a tree iterator is more complex than the implementation of an iterator used by structures that implement the
List interface. We will show how to construct an iterator 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 algorithms. 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 display 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 concepts and is discussed as an application in Section 17.4.
arithmetic expression. These formats specify the position of a binary operator and its operands. In postfix notation, 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.
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.
FORDMC17_0130477249v3.qxd
506
11/12/04
Chapter 17
5:05 PM
An expression
tree represents
an arithmetic
expression.
In an expression
tree, each operator is an interior
node whose children are operands
or subexpressions. Operands
are in leaf nodes.
Page 506
Postfix
Prefix
a*b
a+b*c
a+b*c/de
ab*
abc*+
abc*d/+e
*ab
+a*bc
+a/*bcde
Assume an arithmetic expression involves the binary operators addition (+), subtraction (-), 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.
*
c
(b) a b* c
(a) a*b
(c) a b*c/d e
Preorder (Prefix):
Inorder (Infix):
Postorder (Postfix):
+ a / * b c d e
a + b * c / d e
a b c * d / + e
// preorder scan
// inorder scan
// postorder scan
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 507
Section 17.1
Expression Trees
507
a
top
Steps 23: Recognize b and c as operands, construct leaf nodes, and push their references onto the stack.
c
top
Step 4:
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.
FORDMC17_0130477249v3.qxd
508
11/12/04
Chapter 17
5:05 PM
Page 508
c
top
Step 5:
c
top
Step 6:
Build an expression tree from the
postfix input by
modifying the
postfix expression
evaluation
algorithm from
Chapter 14.
We have reached the end of the expression. The single item on the stack is
the root of the expression tree.
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 509
Section 17.1
Expression Trees
509
operator or an operand
== '-' ||
== '/')
operator; pop two subtrees off
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.
FORDMC17_0130477249v3.qxd
510
11/12/04
Chapter 17
5:05 PM
Page 510
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 511
Section 17.2
511
A tree iterator
scans the elements as if the
tree were linear.
T
interface
Iterator
hasNext(): boolean
next(): T
remove(): void
InorderIterator
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.
FORDMC17_0130477249v3.qxd
512
11/12/04
Chapter 17
5:05 PM
Page 512
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.
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 remember 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 discovered 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).
Stack
Stack
Visit B
Visit F
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 513
Section 17.2
513
Stack
Stack
Visit A
Visit D
F
(c) By rule 3, the node is D
Pop D from the stack
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).
Stack
Stack
Visit E
Visit C
F
(e) By rule 2, the next node is E
Push C on the stack
At node C, rule 3 applies. The stack is empty, and the scan is complete.
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.
FORDMC17_0130477249v3.qxd
514
11/12/04
Chapter 17
5:05 PM
Page 514
UnsupportedOperationException. In reality, an InorderIterator object is designed 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 becomes 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 execute 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);
}
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 515
Section 17.2
515
The method next() implements Steps 1 through 3. In keeping with the requirements 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;
}
3:15
18:35
20:55
10:45
12:00
5:15
7:30
15:30
9:15
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.
FORDMC17_0130477249v3.qxd
516
11/12/04
Chapter 17
5:05 PM
Page 516
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
import
import
import
ds.util.TNode;
ds.util.BinaryTree;
ds.util.InorderIterator;
ds.time.Time24;
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 517
Section 17.3
517
Run:
Original tree
3:15
18:35
20:55
10:45
12:00
5:15
7:30
15:30
9:15
Modified tree
4:15
19:35
21:55
11:45
13:00
6:15
8:30
16:30
10:15
FORDMC17_0130477249v3.qxd
518
11/12/04
Chapter 17
5:05 PM
Page 518
// on the left
// from below
// 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 equivalent 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 (operator), 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
s += t.nodeValue;
else
{
s += "(";
s += fullParen(t.left);
s += t.nodeValue;
s += fullParen(t.right);
s += ")";
}
}
return s;
== null)
// visit a leaf node
// visit on left
// visit from below
// visit on right
}
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 519
Section 17.3
519
Run:
Enter a postfix expression: a d e * b c / +
Expression tree
+
*
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.
FORDMC17_0130477249v3.qxd
520
11/12/04
Chapter 17
5:05 PM
Page 520
col0
level 0
A
B
level 1
C
D
col1
col3
col4
A
B
C
D
level 2
col2
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.
left
nodeValueStr
level
column
right
TNodeShadow object
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 521
Section 17.4
521
TNodeShadow class:
class TNodeShadow
{
public static int columnValue;
public String nodeValueStr;
public int level, column;
public TNodeShadow left, right;
public TNodeShadow ()
{}
}
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.
FORDMC17_0130477249v3.qxd
522
11/12/04
Chapter 17
5:05 PM
Page 522
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.
col0
col1
level 0
level 1
level 2
col2
col3
col4
A
B
C
D
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 523
Section 17.4
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 combines with the value of colWidth to specify how far we must move to the right before inserting 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 displayed. 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 documentation comments in the code listing allow you to understand the remaining details of
the method implementation.
523
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();
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.
FORDMC17_0130477249v3.qxd
524
11/12/04
Chapter 17
5:05 PM
Page 524
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 subexpression. The method buildExpTree() takes a string argument specifying a postfix expression 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 recursion. 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 iterative traversal of a binary tree. Essentially, the stack simulates the recursion.
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 525
Programming Exercises
525
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 expression 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 contain the data of the original tree node formatted as a string along with data that specify the position of the node in tree display. A subsequent level-order scan outputs the
tree display.
Written Exercises
1. Write the infix expression
a + 2*b
+ 8*e
(c + d)
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 expression. Give an example to illustrate your argument.
3. Why is developing an iterator for a binary tree a more difficult problem than developing 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().
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.
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.
FORDMC17_0130477249v3.qxd
526
11/12/04
Chapter 17
5:05 PM
Page 526
For instance, if alist = 51, 2, 3, 4, 56, buildCTree() should construct the complete tree.
(c) Implement method buildCCharTree() that constructs a complete tree containing 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 reference 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;
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 527
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 subtree. 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 postfix 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 program 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 references. 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.
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.
FORDMC17_0130477249v3.qxd
528
11/12/04
Chapter 17
5:05 PM
Page 528
Visit A. Go left.
Push C
...
...
C
top
top
B
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.
#8
#3
#0
#3
#1
#0
#2
#0
#0
Tree 1
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.
FORDMC17_0130477249v3.qxd
11/12/04
5:05 PM
Page 529
Programming Project
529
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 between 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
state = = 0, motion is down the tree. If state = = 1, 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.
(b) Write a program that creates Tree 0, Tree 1, and Tree 2. Using PostorderIterator,
output the postorder traversal for each tree.
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.