我正在阅读这本书"破解编码面试"通过Gayle McDowell发现了一个有趣的递归算法,该算法对平衡二叉搜索树中所有节点的值进行求和。
int sum(Node node) {
if (node == null) {
return 0;
}
return sum(node.left) + node.value + sum(node.right);
}
现在Gayle说运行时是O(N)我觉得很困惑,因为我不知道这个算法将如何终止。对于给定节点,当node.left在第一次调用中传递给sum,然后node.right因此在第二次调用中传递给sum时,不是算法第二次计算sum(节点) ?这个过程不会永远持续下去吗?我还不熟悉递归算法,所以它可能不是很直观。
干杯!
答案 0 :(得分:1)
这个过程不会永远持续下去。有问题的数据结构是平衡二进制搜索树,而不是可以包含循环的图。
从root开始,所有节点都将以left -> itself -> right
的方式进行探索,就像深度优先搜索一样。
node.left
将探索节点的左子树,node.right
将探索同一节点的右子树。两个子树都没有交叉。绘制程序控制的轨迹以查看探索节点的顺序,并查看遍历中没有重叠。
由于每个节点只被访问一次,并且当一个叶节点被命中时递归将开始展开,运行时间将是O(N),N是节点数。< / p>
答案 1 :(得分:-1)
理解递归算法的关键是相信它能够做到它所认为的那样。让我解释一下。
首先承认函数sum(node)
返回以node
为根的子树的所有节点的值的总和。
然后是代码
if (node == null) {
return 0;
}
return sum(node.left) + node.value + sum(node.right);
可以做两件事:
如果节点为null
,则返回0
;这是一个非递归的情况,返回的值非常正确;
否则,函数会计算左子树的总和加上node
的值加上右子树的总和,即根据node
生成的子树的总和。
所以在某种程度上,如果函数是正确的,那么它是正确的:)实际上,由于非递归的情况,这个论证不是循环的,这也是正确的。
我们可以使用相同的推理方式来证明算法的运行时间。
假设处理以节点为根的树所需的时间与此子树的大小成比例,请|T|
。这是另一种信仰行为。
如果node
为空,则时间是常数,让1
为单位。如果node
不为空,则时间为|L| + 1 + |R|
个单位,正好是|T|
。因此,如果对子树求和的时间与子树的大小成正比,那么求和树的时间与树的大小成正比!