University of California, Berkeley
EECS Department - Computer Science Division
CS3 Lecture 20 : Trees
Overview of today's lecture
Review
Lists
- We saw lists, the underlying data structure of scheme.
- We saw how sentences were specializations of lists.
- We saw association lists, useful for storing data
in tables.
- We saw recursion on arbitrary structured lists, known as
car-cdr recursion
Trees
|
|
...how Computer Scientists think of trees. |
Example tree of the world |
Overview
- Trees are a very common computer science data structure.
- They are used for representing a hierarchy, and/or
data that captures parent-child relationships.
- Trees have nodes and branches, which connect
the nodes.
- There are three types of nodes:
- root node (the uppermost node)
- inner node (non-leaves that are not the root)
- leaf nodes (nodes with no branches below it)
- Smaller sections of the tree are called subtrees.
- The nodes below a node are called children.
- The node above a node is called the parent.
- If each node of a tree has two or fewer children, it is called
a binary tree.
- What is a node?
- Students sometimes get confused (other textbooks sometimes
do too!)
- A node is not just the name USA, it's the entire subtree!
- What's the difference between a tree and a node? Nothing!
- Even a node of a tree is a tree, even a leaf!
- When I want to talk about USA, I'll ask for the datum
of this node.
- Each node has a datum and 0 or more children.
- The datum is typically a word or number or sentence, something
small.
- E.g., USA has 50 children (+ 2 commonwealths)
What good are trees?
- When data is hierarchical, it's useful to group them this
way, certainly more useful than a list.
- Examples of other hierarchical data?
- Questions to ask of hierarchies:
- Where is Berkeley? [Earth : USA : California : Berkeley]
- (find-place 'berkeley world)
- How many children does Berkeley have? [4 that are listed]
- How far down is Berkeley from the root? [2 steps]
- What's the biggest fanout of any node? [52 ]
- Who are the children of Berkeley? [Northside, Southside,
Eastside, Westside]
- Who is Berkeley's parent? [USA]
- We would also like to write programs to be able to answer
these questions for us.
Selectors and Constructors
- With any new data structure, we have constructors and selectors:
- (make-node datum children) ==> tree
(aka node)
- This is the only constructor for our trees, it returns a
tree
- datum is any data we want to store by the
tree
- children is the list of other trees,
possibly null (i.e., ())
- (datum node) ==> datum
- This selector takes a tree's node and returns the datum
for that node.
- (children node) ==> list-of-trees
- This selector takes a tree's node and returns the datum
for that node.
- Thoughts:
- How would we write leaf? which returns #t iff
the node is a leaf (has no children)
(define (leaf? node)
==>
- children returns a list of trees,
which is called a forest
- Three data types so far:
- <whatever datatype is at the datum>
- tree
- forest (i.e., list of trees)
- Time-saving functions:
(define (make-leaf datum) ;; called leaf in the book
(make-node datum '()))
(define (make-leaves datum-list) ;; called cities in the book
(map make-leaf datum-list))
Representing Trees as Lists
- Just as with sets, we can use Scheme's underlying list representation.
- We can represent a tree as a list of the elements:
- (root-datum child1 child2 ... childN)
- The children, or subtrees (if any) are trees themselves
- This definition is recursive!
- Our constructors and selectors could be implemented as follows:
(define (make-node datum children)
(cons datum children))
(define (datum node)
(car node))
(define (children node)
(cdr node))
- We'll also see why car/cdr recursion is often called
tree-recursion!
- Let's now look at a very simple example...
Example: California and 3 Cities
|
*our-state*
(California and 3 cities)
- Pretend CA has three cities of interest:
- It's represented as:
(root-datum child1 child2 ... childN)
(ca (sf) (berkeley) (la))
|
Tree |
Representation in Scheme |
- Why is the following wrong?
(make-node 'ca (list 'sf 'berkeley 'la))
- Ans: Second argument isn't children, it's a list
of datum, which is wrong.
- Howabout this proposal?
(make-node 'ca (list (cons 'sf '()) (cons 'berkeley '()) (cons 'la '())))
- Ans: This is a Data Abstraction Violation (DAV)! We
need to use constructors...
: (make-node 'ca
(list (make-node 'sf '())
(make-node 'berkeley '())
(make-node 'la '())))
(ca (sf) (berkeley) (la))
- Or we can use make-leaves:
: (define *our-state* (make-node 'ca (make-leaves '(sf berkeley la)))
(ca (sf) (berkeley) (la))
Abstract Data Types (ADT)
- The constructors and selectors make-tree, datum
and children define an absctract data type (ADT)
for trees
- If we wanted to get to berkeley from our-state, which of
the following are correct?
- : (first (first (bf (bf *our-state*))))
berkeley
- Right or wrong and why? ==>
- : (caaddr *our-state*)
berkeley
- Right or wrong and why? ==>
- What's the right way to do it? ==>
Another example: *number-tree*
- Let's look at another example which is a tree of numbers
|
*number-tree*
- This is the same idea as the worlds tree above
- You can think of this tree as representing the apartment
#s of a family. Grandpa lives at #6, his two children at #2 and
#4, etc.
(root-datum child1 child2 ... childN)
(define *number-tree*
(make-node
6
(list (make-node 2 (make-leaves '(3 8)))
(make-node
4
(list (make-leaf 16)
(make-node 1 (make-leaves '(10 4))))))))
(6 (2 (3) (8)) (4 (16) (1 (10) (4))))
|
Tree |
Representation in Scheme |
Mutual Recursion Example : tree-every
- First, let's recall every:
(define (my-every fn s)
(if (empty? s)
'()
(se (fn (first s))
(my-every fn (bf s)))))
- We'll now define tree-every to do something to every
element of a tree.
- Note that tree-every calls tree-every-forest
and tree-every-forest calls tree-every
- This is called mutual recursion!
(define (tree-every fn node)
(make-node (fn (datum node))
(tree-every-forest fn (children node))))
(define (tree-every-forest fn forest)
(if (null? forest)
'()
(cons (tree-every fn (car forest))
(tree-every-forest fn (cdr forest)))))
: (tree-every square *number-tree*)
(36 (4 (9) (64)) (16 (256) (1 (100) (16))))
- Let's now define tree-every-using-map which will
do both recursions for us
- What appears to be missing? Base cases! Where are they?
- ANS: They're all in the map... There are two base
cases:
- We're going through the forest and we've hit the last child
-- map automatically stops
- We're at a leaf and there are no children. map called
with a null list doesn't call the procedure!
(define (tree-every-using-map fn node)
(make-node (fn (datum node))
(map (lambda (child) (tree-every-using-map fn child))
(children node) )))
: (tree-every-using-map square *number-tree*)
(36 (4 (9) (64)) (16 (256) (1 (100) (16))))
Another example: tree-sum
- The following example shows how to add the elements of a
tree
(define (tree-sum node)
==>
==>
: (tree-sum *value-tree*)
54
- Does this remind you of car/cdr recursion?
Sample problems
- (substitute-tree tree old new)
- Substitute the old element for the new
element in the tree. E.g.,
- : (substitute-tree *number-tree* 4 99)
==> (6 (2 (3) (8)) (99 (16) (1 (10) (99))))
- (count-elts-in-tree tree elt)
- Return the number of times the element elt appears
in the tree. E.g.,
- : (count-elts-in-tree *number-tree* 4)
==> 2
- (smallest-tree-element tree)
- Return the smallest element in the tree. E.g.,
- : (smallest-tree-element *number-tree*)
==> 1
- (update-nodes tree)
- Assuming the non-leaf elements of a tree should be the sum
of the children, update them to reflect this (they may not be
correct when passed as input) E.g.,
- : (update-nodes *number-tree*)
==> (41 (11 (3) (8)) (30 (16) (14 (10) (4))))
Summary
- Today we've seen trees and tree recursion, useful for hierarchical
data!
Next Time
- We'll look at input and output
Puzzle : What Color is your Hat? [Former
CS3 superstudent Alex Kozlowski]
- Four people are waiting in a line facing the same direction,
the right, and the one in the rear is asked to turn around
- They are all told to close their eyes while a hat (chosen
from a bag of two white hats and two black hats) is randomly
placed on each one.
- Whenever someone logically deduces what color hat they have
on (they know there are a total of 2 whites and 2 blacks) they
get a prize.
- They open their eyes...after about a minute, someone says
"I know what color my hat is!".
- Who was it and how did they figure it out?
(rear) <O O> O> O> (front)
Game : Four in a Row (aka "Connect
Four") ["Pentagames" by Pentagram, Fireside Publishing,
1990]
- Draw a grid of six by seven dots. The game is played as fast
as possible from the bottom upwards.
- The first player chooses a dot on the bottom row and marks
it. The other player then chooses one either on the row or directly
above the opponent's, and does the same.
- Each player continues to mark a dot, playing upwards and
aiming to get four in a row either horizontally, vertically or
diagonally, or blocking his opponent from doing so.
- The winner is the first to get four in a row.
Blank Board |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
o |
|
|
o |
|
o |
|
x |
o |
x |
o |
o |
x |
|
x |
x |
o |
o |
x |
x |
x |
x |
x |
o |
x |
o |
o |
Example Game (o won) |