反模式检测
。此页面上的其他答案已经被犯同样的错误
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
这就是说retu RN的(sum, count)
其中
- 一个元组为总和,这个节点的数据加上无论左右的款项是
- 为计数,算上这个节点(1),加上左不管,右计数是
通过编写这种方式,我们可以非常清楚的看到这两种情况我们的函数来处理:
- 当一个节点为
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)
如果您和我一样,尽管事实上这是对使用重新分配的其他答案的巨大改进,但它仍然使用中间值。如果我们可以稍微清理一下,我们会很高兴的。
如果我们有一个函数可以获取元组列表并将所有值添加到它们各自的位置,该怎么办?
// 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
当然,它的工作原理和以前一样,只是现在它只是一样美丽即可。
'_,'是什么意思? –
我明白你的意思了,但请解释上面的语法? –
@VeeshaDawg我已经扩大了答案。 –