Lecture
18: Tree
Traversals
Announcements
·
p4 (Dictionary + Document Word Count) is
due 4/14
·
h6 due today; h7 posted (due )
it's
often useful to iterate through a tree's nodes
o
visit each node once
e.g., to print
all values, search for a value, etc.
·
four common orderings for traversing the
nodes
o
preorder
o
postorder
o
level order
o
in-order (binary trees only)
preorder
traversal ("visit the root first")
recursive
definition:
1.
visit the root
2.
do a preorder traversal of the 1st
subtree
3.
do a preorder traversal of the 2nd
subtree
4.
do a preorder traversal of the 3rd
subtree
etc., for all subtrees, left to right
example:
preorder
traversal & print: A B D C E G F H I
code
for preorder traversal
preorder(Treenode T) {
if (T != null) {
// visit
T; e.g., print T
List tmp = T.getKids();
for (int k=0; k < tmp.size(); k++){
preorder(tmp.get(k));
}
}
}
postorder traversal ("visit the root
last")
1.
do a postorder
traversal of the 1st subtree
2.
do a postorder
traversal of the 2nd subtree
etc.
for all subtrees, left to right
3.
visit the root
postorder
traversal & print: D B G E H I F C A
in-order
traversal (binary trees only)
"visit the root inbetween the left
and right subtrees"
1.
do an in-order traversal of the left subtree
2.
visit the root
3.
do an in-order traversal of the right subtree
inorder
traversal & print: D B A G E C H F I
Note: the difference between pre- in- &
post-order is
when
the root is visited with respect to its subtrees
pre: visit the root before the subtrees
in: visit the root in between the subtrees
post:
visit the root after the subtrees
level-order traversal
1.
visit all the nodes at level 1
2.
visit all the nodes at level 2
etc. (always left to
right)
·
use a Queue
(recursion for pre-/post- order uses a Stack)
Q.enqueue( root );
while (!Q.isEmpty())
{
// dequeue node n
// visit n; e.g.,
print n
// enqueue all of n's children, left
to right
}
(simulate the example with visit =
print)
You
try:
give
the output for
pre-order, in-order,
post-order & level-order traversals of
I
laughed (ha!)
and jumped ate cakes
he she all
five
pre-order: I laughed and he jumped she (ha!) ate all 5
cakes
in-order: and he laughed she jumped I all ate 5 (ha!)
cakes
post-order: he and she jumped laughed all 5 ate cakes
(ha!) I
level-order: I laughed (ha!) and jumped ate cakes he she
all 5
Binary Search Trees
BSTs
·
important special kind of binary tree
·
each node stores a key value
& maybe
some associated data
·
for every node n:
o
all keys in n's
left subtree are £ the key at n
o
all keys in n's
right subtree are ³ the key at n
if
duplicate keys are allowed, keys =
the key at n
all go in
either the left or the right subtree
(but not in both – need a convention)
BSTs
are important because we can do:
·
insert a key (and associated data)
·
lookup a key (return true or associated
data)
·
remove a key
·
print all keys in sorted order
easily
and efficiently
examples:
each key is an int
YES NO (7 ! £ 6)
each key is a char
YES NO (F not ³ G)
Question:
what kind of
traversal prints the BST keys in sorted order?
answer: an in-order traversal
Implementing BSTs
Two
classes: one for tree nodes, one
for "whole tree"
class Bnode
{
public Comparable key;
// can be private - in notes
public Bnode left, right;
// the
constructor goes here
// get, set
methods for any private fields go here
}
class BST {
private Bnode root;
public BST() { root = null; }
public void insert( Comparable k ) throws DupEx { … }
public boolean lookup( Comparable
k ) { … }
public void delete( Comparable k ) { … }
public void print( PrintWriter p )
{ … }
}
Note: can have associated data with each node
e.g., key =
English word, associated data = French
word
how would each
of the above change for associated data?
1.
Bnode
has a 4th field:
public Object data;
2.
insert has two parameters: (Comparable k, Object d)
3.
lookup returns associated data (null if key
not in BST)
4.
delete might return data of deleted key
BST's
lookup method
1.
if the tree is empty, return false
2.
if given key is at the root, return true
3.
if the given key is less than the value in
the root,
return
lookup on the left subtree
4.
if the given key is greater than the value
in the root,
return
lookup on the right subtree
want
a recursive method with two parameters:
key & root
thus, use an
auxiliary method
public Boolean lookup(Comparable
k) {
return lookup(root,k); // lookup is overloaded
}
private static Boolean lookup(Bnode n, Comparable k) {
if (n == null) return false; // base case
if (n.key.equals(k)) return true;
// base case
if (k.compareTo(n.key) < 0) return lookup(n.left,
k);
else return lookup(n.right, k);
}
Simulate
together:
lookup(3)
155
lookup(4)
lookup(9)
sound
effects:
empty
(null): bird; look left: slide up
value found: bell;
look right: slide down
Time
for lookup
·
always follows a path from the root down
·
worst case:
goes all the way to a leaf
thus,
worst case time is proportional to height of the tree
how
does height relate to N = # nodes (i.e.,
# keys) in tree?
·
depends on the shape of the tree
o
best case:
tree is balanced
all
non-leaf nodes have two children
all
leaves are at depth = height
height
is O(log N) where N = number of
nodes
o
worst case:
tree is linear
all
non-leaf nodes have just one child
height
is O(N)
Summary
·
worst case time for lookup: O(h),
h = height of tree
·
worst of the worst: height is O(N), N =
# nodes in tree
·
on average:
height is ~ log N
Note: log N is much better than N for large N
N: 32
64 128 …
1024 1,000,000
log
N: 5 6
7 … 10 20
insert(k)
·
a new value is always inserted as a leaf
·
must choose position to respect BST
ordering
·
attempt to insert a duplicate key is
an error
algorithm:
1.
if BST is empty, make the new value be at
the root
2.
else,
·
find node that will be the parent of the
new node
(using "binary search")
·
create new node and make it the appropriate
child of the parent