该算法应该计算二叉树中数字的总和。为了证明它的正确性,有两个重要的事实需要证明:首先它确实计算了它访问的节点的总和,其次它访问了每个节点一次。因此,我们需要找到至少两个不变量,一个用于证明这些事实中的每一个。
为了更正式地讨论“已访问”或“未访问”节点,让我们在算法中添加几行代码,以跟踪“已访问”节点列表。这些行显然不会改变算法的行为,因为visited
只写入,从不读取:
def TreeSum(root):
res = 0
s = Stack()
s.push(root)
visited = [] # added line to simplify proof
while s.size > 0:
node = s.pop()
visited.append(node) # added line to simplify proof
res = res + node.num
if node.right != None:
s.push(node.right)
elif node.left != None:
s.push(node.left)
return res
我还添加了算法所必需的一行,让它s
成为一个新堆栈,否则要么s
没有定义,要么如果它是一个全局变量,那么我们不能保证在算法启动时它是空的。
所需的不变量如下:
res
等于a.num
for的总和a in visited
。
- 对于所有节点
a in visited
,以及c not in visited
作为 的后代的所有节点a
,c in s
或者有一个唯一的节点b in s
,它b
是 的后代a
和祖先c
。
- 要么
root in s
要么root in visited
。
需要第三个不变量来得出结论,visited
当循环终止时包含每个节点,因此这res
是每个节点的总和。没有这个,其他两个不变量在visited
为空且res
为 0 时得到满足,但第三个不变量允许我们拒绝这种可能性。