1 of 46

Announcements

Pre-spring break survey coming later today. Complete for extra credit.

HW3 is out. Due next Thursday.

  • Write a priority-queue based AI to solve a vast family of problems including Rubik’s Cubes, sliding-tiles puzzles, etc.

Guerrilla section Saturday. Covers all material up to today with a focus on hashing.

  • 12-2pm in 273 and 275 Soda.

2 of 46

CS61B

Lecture 25: Advanced Trees

  • Tree Traversals
  • Level Order Traversal
  • Range Finding
  • Spatial (a.k.a. Geometric) Trees
  • Tree Iterators (Extra)

3 of 46

Traversals

4 of 46

Rooted Trees

We’ve used BSTS to build Maps and Sets, and Heaps to build a PQ.

… but trees are a more general concept.

proj1

synthesizer

spec

GuitarHeroLite.java

hw1.md

karplus-strong.png

...

skeleton

proj0

audio

data

...

...

...

...

planets.txt

5 of 46

Rooted Trees

Given such a tree, find how much disk space all the files use.

  • What one might call “tree iteration” is usually called “tree traversal.”
  • Unlike lists, there are many natural orderings.

proj1

synthesizer

spec

GuitarHeroLite.java

hw1.md

karplus-strong.png

...

skeleton

proj0

audio

data

...

...

...

...

planets.txt

6 of 46

Tree Traversal

Level Order

  • Traverse top-to-bottom, left-to-right (like reading in English):
  • We say that the nodes are ‘visited’ in the given order.

Depth First Traversals

  • Preorder, Inorder, Postorder
  • Basic (rough) idea: Traverse “deep nodes” (e.g. A) before shallow ones (e.g. F).

A

C

B

D

E

F

G

7 of 46

Depth First Traversals

Preorder: “Visit” a node, then traverse its children:

A

C

B

D

E

F

G

preOrder(BSTNode x) {

if (x == null) return;� print(x.key)� preOrder(x.left)� preOrder(x.right)}

A

B

C

D

E

F

G

8 of 46

Depth First Traversals

Preorder traversal: “Visit” a node, then traverse its children: DBACFEG

Inorder traversal: Traverse left child, visit, then traverse right child:

A

C

B

D

E

F

G

inOrder(BSTNode x) {

if (x == null) return;� inOrder(x.left)� print(x.key)

inOrder(x.right)}

preOrder(BSTNode x) {

if (x == null) return;� print(x.key)� preOrder(x.left)� preOrder(x.right)}

A

B

C

D

E

F

G

9 of 46

Depth First Traversals http://shoutkey.com/on

Preorder traversal: “Visit” a node, then traverse its children: DBACFEG

Inorder traversal: Traverse left child, visit, traverse right child: ABCDEFG

Postorder traversal: Traverse left, traverse right, then visit: ???????

A

C

B

D

E

F

G

postOrder(BSTNode x) {

if (x == null) return;� postOrder(x.left)

postOrder(x.right)� print(x.key)

}

  1. DBACEFG
  2. GFEDCBA
  3. GEFCABD
  4. ACBEGFD
  5. ACBFEGD
  6. Other

10 of 46

Depth First Traversals

Preorder traversal: “Visit” a node, then traverse its children: DBACFEG

Inorder traversal: Traverse left child, visit, traverse right child: ABCDEFG

Postorder traversal: Traverse left, traverse right, then visit: ACBEGFD

A

C

B

D

E

F

G

  • DBACEFG
  • GFEDCBA
  • GEFCABD
  • ACBEGFD
  • ACBFEGD
  • Other

postOrder(BSTNode x) {

if (x == null) return;� postOrder(x.left)

postOrder(x.right)� print(x.key)

}

11 of 46

A Weird Trick

  • Preorder traversal: We walk the graph, from top going counter-clockwise. Shout every time we pass the LEFT of a node.
  • Inorder traversal: Shout when you cross the bottom.
  • Postorder traversal: Shout when you cross the right.

Example: Post-Order Traversal

  • 4 7 8 5 2 9 6 3 1

9

4

2

1

3

6

8

5

7

12 of 46

What Good Are All These Traversals?

Example: Preorder Traversal for printing directory listing:

python

sc2APM

directOverlay

notes

directO.sln

directO.suo

directIO

printAPM.py

DXHookD3D11.cs

Injector.cs

13 of 46

What Good Are All These Traversals?

Example: Postorder Traversal for gathering file sizes.

python

sc2APM

directOverlay

notes

directO.sln

directO.suo

directIO

printAPM.py

DXHookD3D11.cs

Injector.cs

18381

8798

38912

881

324

874

postOrder(BSTNode x) {

if (x == null) return 0;� int total = 0;

for (BSTNode c : x.children())� total += postOrder(c)� total += x.fileSize();

return total;�}

14 of 46

What Good Are All These Traversals?

Example: Postorder Traversal for gathering file sizes.

python

sc2APM

directOverlay

notes

directO.sln

directO.suo

directIO

printAPM.py

DXHookD3D11.cs

Injector.cs

18381

8798

38912

881

324

874

postOrder(BSTNode x) {

if (x == null) return 0;� int total = 0;

for (BSTNode c : x.children())� total += postOrder(c)� total += x.fileSize();

return total;�}

27179

66972

874

68170

15 of 46

Visitor Pattern (Patterns)

When writing general tree traversal code. Avoid rewriting traversal for every task of interest (print, sum filesizes, etc.) by using the Visitor pattern.

void preorderTraverse(Tree<Label> T, Action<Label> whatToDo) {

if (T == null) { return; }

whatToDo.visit(T); /* before we hard coded a print */

preorderTraverse(T.left, whatToDo);

preorderTraverse(T.right, whatToDo);

}

interface Action<Label> {

void visit(Tree<Label> T);

}

class FindPig implements Action<String> {

boolean found = false;

@Override

void visit(Tree<String> T) {

if ("pig".equals(T.label))

{ found = true; }

}

}

preorderTraverse(someTree, new FindPig());

16 of 46

Preorder Traversal Runtime: http://shoutkey.com/what

What is the runtime of a preorder traversal in terms of N, the number of nodes? (in code below, assume the visit action takes constant time)

  1. Θ(1)
  2. Θ(log N)
  3. Θ(N)
  4. Θ(N log N)
  5. Θ(2N)

e

b

g

a

d

f

j

v

p

y

m

r

x

z

k

void preorderTraverse(Tree<Label> T, Action<Label> whatToDo) {

if (T == null) { return; }

whatToDo.visit(T);

preorderTraverse(T.left, whatToDo);

preorderTraverse(T.right, whatToDo);

}

17 of 46

Preorder Traversal Runtime

What is the runtime of a preorder traversal in terms of N, the number of nodes? (in code below, assume the visit action takes constant time)

3. Θ(N) : Every node visited exactly once. Constant work per visit.

Runtime is exponential in height of the tree, not number of items.

  • Θ(2H), but H = Θ(log N)
  • This is not a proof of runtime, but rather a response to a possible objection.

e

b

g

a

d

f

j

v

p

y

m

r

x

z

k

N = 15

H = 3

18 of 46

Level Order Traversal

19 of 46

Tree Traversal: Level Order Traversal

The Level Order Traversal is the result of reading the nodes “like a book”, one level at a time.

How would we implement a level order traversal?

  • Level order: D B F A C E G
  • Goal: Visit nodes on 0th level, then 1st level, then 2nd level, etc.

A

C

B

D

E

F

G

20 of 46

Level-Order Traversal through Iterative Deepening

Run visitLevel H times, one for each level.

A

C

B

D

E

F

G

The strategy described on this slide is called “Iterative Deepening”.

public void visitLevel(Tree T, int level, Action toDo) {

if (T == null)

{ return; }

if (lev == 0)

{ toDo.visit(T.key); }

else {

visitLevel(T.left(), lev - 1);

visitLevel(T.right(), lev - 1);

}

}

public void levelOrder(Tree T, Action toDo) {

for (int i = 0; i < T.height(); i += 1) {

visitLevel(T, i, toDo);

}

}

21 of 46

Level-Order Traversal through Iterative Deepening

0

1

0

0

2

1

1

0

0

0

Partially completed Iterative Deepening,

22 of 46

Iterative Deepening Runtime: http://shoutkey.com/sepia

What is the runtime to complete iterative deepening on a complete tree (as shown below) as a function of node count N?

  • Θ(log N)
  • Θ(N)
  • Θ(N log N)
  • Θ(N2)
  • Θ(2N)

0

1

2

0

0

0

0

0

0

0

0

0

0

0

0

2

1

0

2

1

3

1

1

1

1

0

23 of 46

Preorder Traversal and Prefix Expressions

What is the runtime to complete iterative deepening on a complete tree (as shown below) as a function of node count N?

  • Θ(N)

e

b

g

a

d

f

j

v

p

y

m

r

x

z

k

Top level visited: 1

Then top two levels visited: 1 + 2 = 3

Then top three levels visited: 1 + 2 + 4 = 7

Then top four: 1 + 2 + 4 + 8 = 15

Top H levels: 21+22+23+...+2H - H = Θ(N)

Note: Exact sum doesn’t matter, the order of growth (and hence the pattern) is what is important.

Interesting aside: Much harder to solve as “4 visits at level 0” then “6 visits at level 1”, etc.

24 of 46

Iterative Deepening Runtime: http://shoutkey.com/beacon

What is the runtime for iterative deepening on a “spindly” tree?

  1. Θ(log N)
  2. Θ(N)
  3. Θ(N log N)
  4. Θ(N2)
  5. Θ(2N)

v

y

z

k

25 of 46

Iterative Deepening Runtime

What is the runtime for iterative deepening on a “spindly” tree?

  1. Θ(N2)

Top level visited: 1

Then top two levels: 1 + 1 = 2

Then top three levels: 1 + 1 + 1 = 3

Top H levels: H

Total: 1 + 2 + 3 + … + H = H2

H = N - 1, so Θ(N2)

v

y

z

k

26 of 46

Tree Height

For algorithms whose runtime depends on height, difference between bushy tree and spindly tree can be huge!

H = Θ(N)

H = Θ(log(N))

Iterative deepening runtimes: Θ(N) vs. Θ(N2)

  • Note: No simple mapping from height to runtime.
  • Extra for experts: Write a better level order Traversal algorithm.

27 of 46

Range Finding

28 of 46

Geometric Search

Suppose we want an operation that returns all items in a range:

  • public Set<Label> findInRange(Tree T, Label min, Label max)

Example:

  • findInRange(T, “dog”, “elves”)
  • Should return:
    • {“dog”, “elf”}

dog

bag

flat

alf

cat

elf

glut

eyes

29 of 46

Geometric Search

Easy approach, just do a traversal of the whole tree, and use visitor pattern to collect matching items.

Runtime is Θ(N)

class rangeFind implements Action<String> {

private Label min, max;

public Set<Label> inRange;

public rangeFind(Label min, Label max) {

this.min = min; this.max = max;

inRange = new HashSet<Label>();

}

void action(Tree<Label> T) {

if (T.label max && T.label min) {

inRange.add(T.label);

}

}

}

30 of 46

Geometric Search

Suppose we want an operation that returns all items in a range:

  • public Set<Label> findInRange(Tree T, Label min, Label max)

Can avoid need to traverse entire tree by being clever.

Example:

  • findInRange(T, “dog”, “elves”)
  • No need to look:
    • Left of dog.
    • Right of flat.

dog

bag

flat

alf

cat

elf

glut

eyes

Nodes inspected: dog, flat, elf, eyes

Nodes matching: dog, elf

31 of 46

Pruning and findInRange Runtime

Suppose we want an operation that returns all items in a range:

  • public Set<Label> findInRange(Tree T, Label min, Label max)

dog

bag

flat

alf

cat

elf

glut

eyes

Nodes inspected: dog, flat, elf, eyes

Nodes matching: dog, elf

Pruning: Restricting our search to only nodes that might contain the answers we seek.

32 of 46

Pruning and findInRange Runtime

Suppose we want an operation that returns all items in a range:

  • public Set<Label> findInRange(Tree T, Label min, Label max)

dog

bag

flat

alf

cat

elf

glut

eyes

Nodes inspected: dog, flat, elf, eyes

Nodes matching: dog, elf

Pruning: Restricting our search to only nodes that might contain the answers we seek.

Runtime for our search: Θ(log N + R)

  • N: Total number of items in tree.
  • R: Number of matches.

See study guide A-level problems for proof.

33 of 46

Spatial Trees

34 of 46

2D Range Finding

Suppose we want to do range finding on Planets in space.

  • Query: How many objects are in the highlighted rectangle?

Could iterate through all objects in Θ(N) time.

  • But could we do some sort of tree + pruning?

Pruning implies we need some kind of tree, but ...

35 of 46

Building Trees of Two Dimensional Data

So far, we’ve only considered one dimensional data.

  • There exists a total order!
    • 5 < 10
    • “alf” < “elf”

Some data is two dimensional, e.g. the location of Planets.

  • earth.xPos = 1.5, earth.yPos = 1.6
  • mars.xPos = 1.0, mars.yPos = 2.8

If we’re comparing by location:

  • In xPos, Mars < Earth
  • In yPos, Mars > Earth

1.5, 1.6

1.0, 2.8

1.5, 1.6

1.0, 2.8

(1.5, 1.6)

(1.0, 2.8)

X-Based Tree

Y-Based Tree

36 of 46

Handling Multidimensional Data: Quadtrees

Quadtrees:

  • Divide and conquer by splitting 2D space into four quadrants.
    • Store items into appropriate quadrant.
    • Repeat recursively if more than one item in a quadrant.

Definition, quadtree is either:

  • Empty
  • A ‘root’ item at some position (x, y) AND four quadtrees that are northwest, northeast, southwest, southeast of (x, y)
  • Use TWO compares to decide which direction to go.

A

NE

SE

SW

NW

37 of 46

Quadtree Demo

Below: Quadtree Representation of 5 objects in 2D space.

  • Demo: Link

A

NW

NE

SE

SW

B

C

SW

SE

D

E

A

(-1, -1)

(2, 2)

B

(0, 1)

C

D

(1, 0)

E

(-2, -2)

38 of 46

Quadtree Demo

Quadtrees allow us to prune when performing a rectangle search.

  • Basic rule: Prune a branch if the search rectangle doesn’t overlap a quadrant of potential interest.

A

NW

NE

SE

SW

B

C

SW

SE

D

E

A

(-1, -1)

(2, 2)

B

(0, 1)

C

D

(1, 0)

E

(-2, -2)

39 of 46

Tree Iterators (Extra)

40 of 46

Iterators

Suppose we want to iterate through a tree using the : operator.

How can we adapt our traversal code to implement next() and hasNext()?

41 of 46

Iteration: The Obvious Way

One approach: Create an action class that puts visited item in a list.

42 of 46

Iteration: The Obvious Way

One approach: Create an action class that puts visited item in a list.

  • iterator method creates such a list and returns an iterator to it.
  • What’s the downside of this solution?

43 of 46

Iteration: Space-saving Approach

Tricky question: How could convert our recursive traversal into iterative code using a stack?

Observation: Each call to preorderTraverse is the equivalent of putting a call on the call stack.

44 of 46

Iteration: Space-saving Approach

Tricky question: How could convert our recursive traversal into iterative code using a stack?

Observation: Each call to preorderTraverse is the equivalent of putting a call on the call stack.

45 of 46

Iteration: Space-saving Approach

Use our stack-based approach, but use next() instead of looping.

46 of 46

Citations

Title figure: A thing I made (one of the first Java programs I wrote during my teaching career)

Pruning image: https://res.cloudinary.com/dc8hy36qb/image/upload/v1435213404/Fruit-Tree-Pruning-Methods_o7ieen_atkmmq.jpg

Jonathan Shewchuk: Nice intuitive use cases for various traversals.