29 - Tree Traversals PDF

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 54

COMP 250

INTRODUCTION TO COMPUTER SCIENCE


29 - Tree Traversals

Giulia Alberini, Winter 2023


Slides adapted from Michael Langer’s
WHAT ARE WE GOING TO DO TODAY?

 Tree traversals
 Depth first VS Breadth first
 Recursive and Non-recursive (with stack or with queue)
TRAVERSALS
TREE TRAVERSAL

How to visit (enumerate, iterate through, traverse… ) all the nodes


of a tree ?
TREE TRAVERSAL – DEPTH FIRST “PREORDER”

depthFirst (root){
if (root is not empty){
visit root
for each child of root
depthfirst( child )
}
}
TREE TRAVERSAL – DEPTH FIRST “PREORDER”

depthFirst (root){ 1
if (root is not empty){
visit root
for each child of root
depthfirst( child )
}
}

“preorder” traversal: visit the


root before the children
TREE TRAVERSAL – DEPTH FIRST “PREORDER”

depthFirst (root){ 1
if (root is not empty){
visit root 2
for each child of root
depthfirst( child )
}
}

Note that here we are assuming that we iterate


through the children nodes from left to right.
TREE TRAVERSAL – DEPTH FIRST “PREORDER”

depthFirst (root){ 1
if (root is not empty){
visit root 2
for each child of root
depthfirst( child )
} 3

}
TREE TRAVERSAL – DEPTH FIRST “PREORDER”

depthFirst (root){ 1
if (root is not empty){
visit root 2
for each child of root
depthfirst( child )
} 3 4

5
TREE TRAVERSAL – DEPTH FIRST “PREORDER”

depthFirst (root){ 1
if (root is not empty){
visit root 2 7 8
for each child of root
depthfirst( child )
3 4 9 10 11
}
}

5 6
EXAMPLE OF USING A PREORDER TRAVERSAL
We would like to print a hierarchical file system
(visit = print directory or file name)
My
Documents
Documents (directory)
Music (directory)
Eminem (directory)
Music Videos Work Research Lose Yourself (file)
Raffi (directory)
Shake My Sillies Out (file)
Baby Beluga (file)
Eminem Raffi COMP Videos (directory)
250
: (file)
Work (directory)
COMP250 (directory)
Lose Shake my Baby
:
Yourself sillies out Beluga Research (directory)
:
“VISIT” A NODE

“Visit” implies that you do something at that node.

Analogy: you aren’t visiting London UK if you just


fly through Heathrow.
TREE TRAVERSAL – DEPTH FIRST “POSTORDER”
Q: Which node is visited first?

depthFirst (root){
if (root is not empty){
for each child of root
depthfirst( child )
visit root
}
}

“postorder” traversal: visit


the root after the children
TREE TRAVERSAL – DEPTH FIRST “POSTORDER”

depthFirst (root){
if (root is not empty){
for each child of root
depthfirst( child )
visit root
} 1

}
TREE TRAVERSAL – DEPTH FIRST “POSTORDER”

depthFirst (root){
if (root is not empty){
for each child of root
depthfirst( child )
visit root
} 1

2
TREE TRAVERSAL – DEPTH FIRST “POSTORDER”

depthFirst (root){
if (root is not empty){
for each child of root 5
depthfirst( child )
visit root
} 1 4

2 3
TREE TRAVERSAL – DEPTH FIRST “POSTORDER”

depthFirst (root){ 11
if (root is not empty){
for each child of root 5 6 10
depthfirst( child )
visit root
1 4 7 8 9
}
}

2 3
EXAMPLE 1 OF USING A POSTORDER TRAVERSAL: height(v)

4
height(v){
if (v is a leaf)
2 1 3
return 0
else{
1 0 0 2 1 h = 0
for each child w of v
h = max(h, height(w))
0 0 0 1 0 return 1 + h
}
}
0 0

visit = return value of height


EXAMPLE 2 OF USING A POSTORDER TRAVERSAL
What is the total number of bytes in all files in a directory?

My
Documents
numBytes(v){
if (v is a leaf)
return number of bytes at v
Music Videos Work Research else{
sum = 0
for each child w of v
sum += numBytes(w)
Eminem Raffi COMP
250 return sum
}
}
Lose Shake my Baby
Yourself sillies out Beluga
visit = determining the number of bytes for a
node, e.g. If we were to store 'sum' at the node.
depthFirst() – PREORDER VS POSTORDER TRAVERSAL

depthFirst (root){ depthFirst (root){


if (root is not empty){ if (root is not empty){
visit root for each child of root
for each child of root depthfirst( child )
depthfirst( child ) visit root
} }
} }
CALL SEQUENCE OF depthFirst()

When we call depthFirst(root), the a


same call sequence occurs for preorder
vs postorder implementation. b g h

In the example on the rigth, the letter


c d i j k
order corresponds to depthFirst(root)
call order.

e f
Note that the call stack stores information
about the active method calls in a program.
CALL STACK FOR depthFirst(root)
a

b g h

c d i j k

e f
e f
c d d d d d i j k
b b b b b b b b b g h h h h h h h
a a a a a a a a a a a a a a a a a a a a a
Note that the call stack stores information
about the active method calls in a program.
CALL STACK FOR depthFirst(root)
a

b g h

c d i j k

e f
e f
c d d d d d i j k
b b b b b b b b b g h h h h h h h
a a a a a a a a a a a a a a a a a a a a a
Note that the call stack stores information
about the active method calls in a program.
CALL STACK FOR depthFirst(root)
a

b g h

c d i j k

e f
e f
c d d d d d i j k
b b b b b b b b b g h h h h h h h
a a a a a a a a a a a a a a a a a a a a a
Note that the call stack stores information
about the active method calls in a program.
CALL STACK FOR depthFirst(root)
a
Notation: the letters
indicate the call order
b g h of depthFirst(root)

c d i j k

e f
e f
c d d d d d i j k
b b b b b b b b b g h h h h h h h
a a a a a a a a a a a a a a a a a a a a a
EXAMPLE
We used a tree to represent the call stack of the recursive Fibonacci method.

fibonacci(247)

fibonacci(246) fibonacci(245)

fibonacci( 245 ) fibonacci( 244 ) fibonacci(244) fibonacci(243)

fibonacci(244) fibonacci(243) fibonacci(243) fibonacci(242) Etc.


TREE TRAVERSAL IMPLEMENTATIONS

Recursive
 depth first (pre- versus post-order)

Non-Recursive
 using a stack
 using a queue
TREE TRAVERSAL – WITH A STACK

treeTraversalUsingStack(root){
initialize empty stack s
s.push(root)

}
TREE TRAVERSAL – WITH A STACK

treeTraversalUsingStack(root){
initialize empty stack s
s.push(root)
while s is not empty {
cur = s.pop()
visit cur

}
}
TREE TRAVERSAL – WITH A STACK

treeTraversalUsingStack(root){
initialize empty stack s
s.push(root)
while s is not empty {
cur = s.pop()
visit cur
for each child of cur
s.push(child)
}
}
TREE TRAVERSAL – WITH A STACK

treeTraversalUsingStack(root){
initialize empty stack s
s.push(root)
while s is not empty {
What is the order in which
cur = s.pop() the nodes are visited?
visit cur
for each child of cur
s.push(child)
}
}
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK
treeTraversalUsingStack(root){ a
initialize empty stack s
s.push(root)
b g h
while s is not empty {
cur = s.pop()
visit cur c d i j k
for each child of cur
s.push(child)
} e f
}

k
j j j
h i i i i i f
g g g g g g g g g d e e e
a _ b b b b b b b b b b b _ c c c c c c c _
TREE TRAVERSAL – WITH A STACK

a
Q: Is it depth first?

A: Yes, but it visits the children “from b g h


right to left”

c d i j k

Recursive preorder: abcdefghijk


Recursive postorder: cefdbgijkha e f

Non-recursive (stack): ahkjigbdfec


TREE TRAVERSAL – WITH A STACK

treeTraversalUsingStack(root){
Q: Is it preorder or postorder? initialize empty stack s
s.push(root)
A: It’s preorder. while s is not empty {
cur = s.pop()
visit cur
Q: Would move the visit change that?
for each child of cur
A: No… why? s.push(child)
visit cur
}
}
WHAT IF WE USED A QUEUE INSTEAD?

treeTraversalUsingStack(root){ treeTraversalUsingQueue(root){
initialize empty stack s initialize empty queue q
s.push(root) q.enqueue(root)
while s is not empty { while q is not empty {
cur = s.pop() cur = q.dequeue()
visit cur visit cur
for each child of cur for each child of cur
s.push(child) q.enqueue(child)
} }
} }
WHAT IF WE USED A QUEUE INSTEAD?
Queue state at start of the while loop
a
treeTraversalUsingQueue(root){
a initialize empty queue q
q.enqueue(root)
b g h while q is not empty {
cur = q.dequeue()
visit cur
c d i j k for each child of cur
q.enqueue(child)
}
e f }
WHAT IF WE USED A QUEUE INSTEAD?
Queue state at start of the while loop
a

bgh treeTraversalUsingQueue(root){
a initialize empty queue q
q.enqueue(root)
b g h while q is not empty {
cur = q.dequeue()
visit cur
c d i j k for each child of cur
q.enqueue(child)
}
e f }
WHAT IF WE USED A QUEUE INSTEAD?
Queue state at start of the while loop
a

bgh treeTraversalUsingQueue(root){
a initialize empty queue q
gh
ghcd q.enqueue(root)
b g h while q is not empty {
cur = q.dequeue()
visit cur
c d i j k for each child of cur
q.enqueue(child)
}
e f }
WHAT IF WE USED A QUEUE INSTEAD?
Queue state at start of the while loop
a

bgh treeTraversalUsingQueue(root){
a initialize empty queue q
gh
ghcd q.enqueue(root)
hcd b g h while q is not empty {
cur = q.dequeue()
visit cur
c d i j k for each child of cur
q.enqueue(child)
}
e f }
WHAT IF WE USED A QUEUE INSTEAD?
Queue state at start of the while loop
a

bgh treeTraversalUsingQueue(root){
a initialize empty queue q
gh
ghcd q.enqueue(root)
hcd b g h while q is not empty {
cd cur = q.dequeue()
cdijk visit cur
c d i j k for each child of cur
q.enqueue(child)
}
e f }
WHAT IF WE USED A QUEUE INSTEAD?
Queue state at start of the while loop
a

bgh treeTraversalUsingQueue(root){
a initialize empty queue q
gh
ghcd q.enqueue(root)
hcd b g h while q is not empty {
cd cur = q.dequeue()
cdijk visit cur
dijk
c d i j k for each child of cur
ijk q.enqueue(child)
ijkef }
jkef e f }
kef
ef
f
BREADTH FIRST TRAVERSAL

a
For each level i
visit all nodes at level i b g h

c d i j k
Order visited: abghcdijkef

e f
IMPLEMENTATION DETAILS

Recall the “first child, next sibling” implementation

class Tree<T>{
TreeNode<T> root;
:

class TreeNode<T>{
T element;
TreeNode<T> firstChild;
TreeNode<T> nextSibling;
:
}
}
IMPLEMENTATION DETAILS

Recall the “first child, next sibling” implementation


Then when we write
for each child {
:
}
it means
child = cur.firstChild
while(child !=null) {
:
child = child.nextSibling
}
Coming next:
 Binary Trees

You might also like