题目描述
Define a function sprout_leaves
that takes in a tree, t
, and a list of leaves, leaves
. It produces a new tree that is identical to t
, but where each old leaf node has new branches, one for each leaf in leaves
.
For example, say we have the tree t = tree(1, [tree(2), tree(3, [tree(4)])])
:
1
/ \
2 3
|
4
If we call sprout_leaves(t, [5, 6])
, the result is the following tree:
1
/ \
2 3
/ \ |
5 6 4
/ \
5 6
def sprout_leaves(t, leaves):
"""Sprout new leaves containing the labels in leaves at each leaf of
the original tree t and return the resulting tree.
>>> t1 = tree(1, [tree(2), tree(3)])
>>> print_tree(t1)
1
2
3
>>> new1 = sprout_leaves(t1, [4, 5])
>>> print_tree(new1)
1
2
4
5
3
4
5
>>> t2 = tree(1, [tree(2, [tree(3)])])
>>> print_tree(t2)
1
2
3
>>> new2 = sprout_leaves(t2, [6, 1, 2])
>>> print_tree(new2)
1
2
3
6
1
2
"""
"*** YOUR CODE HERE ***"
树的数据抽象如下:
# Tree Data Abstraction
def tree(label, branches=[]):
"""Construct a tree with the given label value and a list of branches."""
for branch in branches:
assert is_tree(branch), 'branches must be trees'
return [label] + list(branches)
def label(tree):
"""Return the label value of a tree."""
return tree[0]
def branches(tree):
"""Return the list of branches of the given tree."""
return tree[1:]
def is_tree(tree):
"""Returns True if the given tree is a tree, and False otherwise."""
if type(tree) != list or len(tree) < 1:
return False
for branch in branches(tree):
if not is_tree(branch):
return False
return True
def is_leaf(tree):
"""Returns True if the given tree's list of branches is empty, and False
otherwise.
"""
return not branches(tree)
def print_tree(t, indent=0):
"""Print a representation of this tree in which each node is
indented by two spaces times its depth from the root.
>>> print_tree(tree(1))
1
>>> print_tree(tree(1, [tree(2)]))
1
2
>>> numbers = tree(1, [tree(2), tree(3, [tree(4), tree(5)]), tree(6, [tree(7)])])
>>> print_tree(numbers)
1
2
3
4
5
6
7
"""
print(' ' * indent + str(label(t)))
for b in branches(t):
print_tree(b, indent + 1)
def copy_tree(t):
"""Returns a copy of t. Only for testing purposes.
>>> t = tree(5)
>>> copy = copy_tree(t)
>>> t = tree(6)
>>> print_tree(copy)
5
"""
return tree(label(t), [copy_tree(b) for b in branches(t)])
分析
这道题使用递归思想解决最为直观,想法为从树的根节点开始,如果当前递归过程传递的子树是叶节点,那么将leaves列表的作为叶节点的各个子树加入树中,如果是非叶结点,那么对其所有子树执行sprout_leaves函数。
问题的实现首先要注意理解树的数据抽象是如何实现的,根据题目给出的定义,树本质上是用列表实现的,列表第一个元素为根节点的值,如果是叶节点,那么列表只有根节点值一个元素,如果是非叶结点,则列表中根节点值后续元素都是列表(树)。因此要将leaves列表添加到原树的每一个叶节点作为其的叶节点,也就是要把leaves列表中的每一个元素转化为树(只有一个根节点),将这些树构成的分支列表与原树的叶节点一起使用tree函数生成一个新的树。
那么考虑sprout_leaves函数的basecase情况,即传入的树t只有一个根节点(is_leaf函数返回True),此时会返回tree(label(t), [tree(leaf) for leaf in leaves]),注意这里要使用方括号将for...in表达式括起来,这样的运算结果会是一个列表(满足tree函数的branches列表的要求,而tree(leaf)会生成只有根节点的树)。
然后考虑递归的实现问题,对于递归函数而言,我们应当假设每个传入相应参数的递归函数都实现了它的功能,如本题中对于任意传入的树t和列表leaves,都实现将leaves加入为t的所有叶节点的叶子的功能。那么本题的递归函数sprout_leaves就很好实现了,如果是basecase情况,就返回tree(label(t), [tree(leaf) for leaf in leaves])得到的树,如果是递归中间过程情况,那么传入的树t有子树,则返回tree(label(t), [sprout_leaves(branch, leaves) for branch in branches(t)]),即根节点不变,所有子树都实现了sprout_leaves功能的树。
代码实现
def sprout_leaves(t, leaves):
"""Sprout new leaves containing the labels in leaves at each leaf of
the original tree t and return the resulting tree.
>>> t1 = tree(1, [tree(2), tree(3)])
>>> print_tree(t1)
1
2
3
>>> new1 = sprout_leaves(t1, [4, 5])
>>> print_tree(new1)
1
2
4
5
3
4
5
>>> t2 = tree(1, [tree(2, [tree(3)])])
>>> print_tree(t2)
1
2
3
>>> new2 = sprout_leaves(t2, [6, 1, 2])
>>> print_tree(new2)
1
2
3
6
1
2
"""
"*** YOUR CODE HERE ***"
if is_leaf(t):
return tree(label(t), [tree(leaf) for leaf in leaves])
return tree(label(t), [sprout_leaves(b, leaves) for b in branches(t)])