In Python, using a class:
python
📄
class Tree:
def __init__(self, label, branches=[]):
self.label = label
self.branches = list(branches)
def is_leaf(self):
return not self.branches
In Scheme, using procedures to build a data abstraction:
scheme
📄
(define (tree label branches)
(cons label branches))
(define (label t) (car t))
(define (branches t) (cdr t))
(define (is-leaf t) (null? (branches t)))
A tree is a recursive structure, where each branch may itself be a tree.
text📄[5, [6, 7], 8, [[9], 10]]
text📄(+ 5 (- 6 7) 8 (* (- 9) 10))
text📄(S (NP (JJ Short) (NNS cuts)) (VP (VBP make) (NP (JJ long) (NNS delays))) (. .))
text📄<ul> <li>Midterm <strong>1</strong></li> <li>Midterm <strong>2</strong></li> </ul>
Tree processing often involves recursive calls on subtrees.
Implement bigs
, which takes a Tree
instance t
containing integer labels. It returns the number of nodes in t
whose labels are larger than all labels of their ancestor nodes.
python
📄
def bigs(t):
"""Return the number of nodes in t that are larger than all their ancestors.
>>> a = Tree(1, [Tree(4, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(2)])])])
>>> bigs(a)
4
"""
python
📄
def bigs(t):
"""Return the number of nodes in t that are larger than all their ancestors.
>>> a = Tree(1, [Tree(4, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(2)])])])
>>> bigs(a)
4
"""
Typical tree processing structure?
python
📄
if t.is_leaf():
return ___
else:
return ___([___ for b in t.branches])
❌ That won't work, since we need to know about ancestors.
python
📄
def bigs(t):
"""Return the number of nodes in t that are larger than all their ancestors.
>>> a = Tree(1, [Tree(4, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(2)])])])
>>> bigs(a)
4
"""
Some code that increments the total count
python
📄
1 + _____
Some way of tracking ancestor labels or max of ancestors seen so far.
python
📄
if node.label > max(ancestors):
python
📄
if node.label > max_ancestor:
python
📄
def bigs(t):
"""Return the number of nodes in t that are larger than all their ancestors.
>>> a = Tree(1, [Tree(4, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(2)])])])
>>> bigs(a)
4
"""
python
📄
# a is the current subtree, x is the largest ancestor
def f(a, x):
if ______________________: # Track the largest ancestor
return 1 + __________ # Increment total
else:
return ______________
return ______________________
python
📄
def bigs(t):
"""Return the number of nodes in t that are larger than all their ancestors.
>>> a = Tree(1, [Tree(4, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(2)])])])
>>> bigs(a)
4
"""
python
📄
def f(a, x):
if a.label > x:
return 1 + sum([f(b, a.label) for b in a.branches])
else:
return sum([f(b, x) for b in a.branches])
return f(t, t.label - 1)
python
📄
def bigs(t):
"""Return the number of nodes in t that are larger than all their ancestors.
>>> a = Tree(1, [Tree(4, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(2)])])])
>>> bigs(a)
4
"""
def f(a, x):
if a.label > x:
return 1 + sum([f(b, a.label) for b in a.branches])
else:
return sum([f(b, x) for b in a.branches])
return f(t, t.label - 1)
Initialize some data structure to an empty/zero value, and populate it as you go.
Implement smalls
, which takes a Tree
instance t
containing integer labels. It returns the non-leaf nodes in t
whose labels are smaller than any labels of their descendant nodes.
python
📄
def smalls(t):
"""Return the non-leaf nodes in t that are smaller than all their descendants.
>>> a = Tree(1, [Tree(2, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(6)])])])
>>> sorted([t.label for t in smalls(a)])
[0, 2]
"""
python
📄
def smalls(t):
"""Return the non-leaf nodes in t that are smaller than all their descendants.
>>> a = Tree(1, [Tree(2, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(6)])])])
>>> sorted([t.label for t in smalls(a)])
[0, 2]
"""
Something which finds the smallest value in a subtree
python📄min(___)
Something which compares smallest to current
python📄t.label < smallest
Something which adds a subtree to a list
python📄__.append(t)
python
📄
def smalls(t):
"""Return the non-leaf nodes in t that are smaller than all their descendants.
>>> a = Tree(1, [Tree(2, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(6)])])])
>>> sorted([t.label for t in smalls(a)])
[0, 2]
"""
python
📄
result = [] # The result list
def process(t): # t is a Tree
if t.is_leaf():
return ______________________
else:
smallest = __________________ # Finds smallest
if _________________________: # Compares smallest
_________________________ # Appends subtree to list
return min(smallest, t.label)
process(t)
return result
python
📄
def smalls(t):
"""Return the non-leaf nodes in t that are smaller than all their descendants.
>>> a = Tree(1, [Tree(2, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(6)])])])
>>> sorted([t.label for t in smalls(a)])
[0, 2]
"""
python
📄
result = []
def process(t):
if t.is_leaf():
return t.label
else:
smallest = min([process(b) for b in t.branches])
if t.label < smallest:
result.append(t)
return min(smallest, t.label)
process(t)
return result
python
📄
def smalls(t):
"""Return the non-leaf nodes in t that are smaller than all their descendants.
>>> a = Tree(1, [Tree(2, [Tree(4), Tree(5)]), Tree(3, [Tree(0, [Tree(6)])])])
>>> sorted([t.label for t in smalls(a)])
[0, 2]
"""
result = []
def process(t):
if t.is_leaf():
return t.label
else:
smallest = min([process(b) for b in t.branches])
if t.label < smallest:
result.append(t)
return min(smallest, t.label)
process(t)
return result
Which strings are matched by each regular expression?
Expressions: | abc | cab | bac | baba | ababca | aabcc | abbaba |
---|---|---|---|---|---|---|---|
[abc]*
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
a*b*c*
| ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
ab|[bc]*
| ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
(a[bc]+)+a?
| ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ |
(ab|ba)+(ab|[bc])?
| ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
What expressions are passed to scheme_eval
when evaluating the following expressions?
scheme
📄
(define x (+ 1 2))
(define (f y) (+ x y))
(f (if (> 3 2) 4 5))