我想创建一个返回树的平均值的函数,在本例中为(5+3+2+6)/(4) = 4
。
我是否预先遍历遍历,这是我的功能:
def helper(root, total=0, amount=0):
if root != None:
total += root.data
amount += 1
helper(root.left, total, amount)
helper(root.right, total, amount)
return (root, total, amount)
def avg(root):
av = helper(root)
return av[1]/av[2]
但是此代码仅返回(Node 5, total = 5, amount = 1)
。它只扫描first
节点,而且我不知道上面代码的原因或错误。
class btn(object):
def __init__(self, data):
self.data = data
self.left = None
self.right = None
答案 0 :(得分:1)
检测到反模式
您已经在使用状态变量的递归 - 不需要使用重新分配来增加更多的复杂性。这个页面上的其他答案因为犯同样的错误而失败了
def avg (tree):
def helper (node, sum, count):
if node is None:
return (0, 0)
else:
(Lsum, Lcount) = helper(node.left, 0, 0)
(Rsum, Rcount) = helper(node.right, 0, 0)
return (node.data + Lsum + Rsum, 1 + Lcount + Rcount)
(sum, count) = helper(tree, 0, 0)
return sum/count if count > 0 else None
# your node class
class Node (object):
def __init__(self, data, left, right):
self.data = data
self.left = left
self.right = right
# make your tree
tree = Node(5, Node(3, Node(2, None, None), None), Node(6, None, None))
print(avg(tree)) #=> 4.0
# ensure that this works for an empty tree too (it does)
print(avg(None)) #=> None
<强>直觉强>
递归使我们能够对此产生非常好的直觉 - 特别是粗体行
(Lsum, Lcount) = helper(node.left, 0, 0)
(Rsum, Rcount) = helper(node.right, 0, 0)
return (node.data + Lsum + Rsum, 1 + Lcount + Rcount)
return
说要返回(sum, count)
的元组
通过这种方式编写,我们可以非常清楚地看到我们的函数必须处理的两种情况:
None
时,我们会为最终计算提供(0, 0)
data
提供给总和,将1
提供给计数。内联代码说明
# we only need to expose one function
def avg (tree):
# helper isn't exposed outside of avg
# helper has stateful parameters
def helper (node, sum, count):
# helper is a recursive function, start with the base case of empty Node
if node is None:
# our base sum and count are 0
return (0, 0)
# process the Node
else:
# get L sum and count the same way we initialized helper with the tree
(Lsum, Lcount) = helper(node.left, 0, 0)
# do the same for the R side
(Rsum, Rcount) = helper(node.right, 0, 0)
# no reassignment of sum or count is necessary,
# simply recurse using the new state values of each
return (
node.data + Lsum + Rsum, # sum equals this node plus L and R sums
1 + Lcount + Rcount # count equals 1 plus L and R counts
)
# always init the sum and count with 0
(sum, count) = helper(tree, 0, 0)
# don't divide by zero if the tree is empty; instead return None
return sum/count if count > 0 else None
清理所有中间值
让我们来看看这个
(Lsum, Lcount) = helper(node.left, 0, 0)
(Rsum, Rcount) = helper(node.right, 0, 0)
return (node.data + Lsum + Rsum, 1 + Lcount + Rcount)
如果你像我一样,尽管这是使用重新分配对其他答案的巨大改进,但它仍然使用 4 中间值。如果我们能够清理一下这一点,那就太好了 - 我们可以。
如果我们有一个可以获取元组列表的函数,并在各自的位置添加所有值,该怎么办?
// if only ...
sum_tuples( (0, 10), (1, 20), (2, 30) )
# ... ( 0 + 1 + 2 , 10 + 20 + 30 )
#=> (3, 60)
事实证明,在zip
的帮助下,该函数实际上很容易编写。这个函数是通用的,所以它在我们的avg
函数以外的地方很有用,所以我将单独定义它
def sum_tuples (*xs):
return tuple(sum(x) for x in zip(*xs))
sum_tuples( (0,10), (1,20), (2,30) )
#=> (3, 60)
现在看看它对avg
的影响 - 不再有中间值(粗体的变化)
def avg (tree):
def helper (node, sum, count):
if node is None:
return (0, 0)
else:
return sum_tuples(
(node.data, 1),
helper(node.left, 0, 0),
helper(node.right, 0, 0)
)
(sum, count) = helper(tree, 0, 0)
return sum/count if count > 0 else None
当然它的工作原理和以前一样,只是现在才变得如此美丽。
答案 1 :(得分:-1)
调用helper
时,您没有使用返回值。这些应该用于确定整个树中的值的总和:
def helper(root, total=0, amount=0):
if root != None:
total += root.data
amount += 1
_, left_total, left_amount = helper(root.left, total, amount)
_, right_total, right_amount = helper(root.right, total, amount)
total += left_total
total += right_total
amount += left_amount
amount += right_amount
return (root, total, amount)
以下行将helper
的返回值“解包”为三个值中的每一个:
_, left_total, left_amount = helper(root.left, total, amount)
这三个值中的第一个值已分配给_
,但被忽略(在这种情况下通常使用变量_
)然后有left_total
和{{1}这是返回的元组中的第二个和第三个值。
答案 2 :(得分:-1)
def helper(root, total=0, amount=0):
if root != None:
total += root.data
amount += 1
(_, total, amount) = helper(root.left, total, amount)
(_, total, amount) = helper(root.right, total, amount)
return (root, total, amount)
你给出了帮助函数的当前总数和金额,但是你没有存储它们返回的新值。