递归模式的大O时间复杂度

时间:2017-11-07 20:09:33

标签: algorithm recursion time-complexity big-o

我对运行时的递归模式有疑问。

示例1

int f(int n) {
  if(n <= 1) {
    return 1;
  }

  return f(n - 1) + f(n - 1);
}

我可以理解上面代码的运行时间是O(2 ^ N),因为如果我传递5,它会调用4两次,然后每次调用3次,然后跟踪直到达到1,即类似O(分支^深度)。

示例2 平衡二进制树

int sum(Node node) {
  if(node == null) {
    return 0;
  }

  return sum(node.left) + node.value + sum(node.right);
}

我读到上面代码的运行时是O(2 ^ log N),因为它是平衡的但我仍然把它看作O(2 ^ N)。谁能解释一下呢?

  1. 当元素数量每次减半时,运行时间为log N.但二叉树如何在这里工作?
  2. 它是2 ^ log N只是因为它是平衡的吗?
  3. 如果不平衡怎么办?
  4. 修改 我们可以求解O(2 ^ log N)= O(N)但我看到它是O(2 ^ N)。

    谢谢!

2 个答案:

答案 0 :(得分:3)

  • 二叉树的复杂性O(n)与此处的任何其他树一样,因为您最终遍历树的所有元素。通过减半,除了分别计算相应孩子的总和之外,我们没有做任何特殊的事情。

  • 这个术语是这样的,因为如果它是平衡的,那么2^(log_2(n))是树中元素的数量(叶子+非叶子)。(log2(n)级别)

  • 如果它不平衡,那也无关紧要。我们正在进行一项操作,需要考虑每个元素使运行时为O(n)

哪里可能有重要意义?如果它正在搜索一个元素,那么它将是重要的(无论它是否平衡)。

答案 1 :(得分:1)

我会捅这个。

在平衡二叉树中,您应该在每个父节点的左侧和右侧有一半的子节点。树的第一层是根,有1个元素,然后是下一层中的2个元素,然后是下一个中的4个元素,然后是8,依此类推。因此,对于具有L层的树,树中有2^L - 1个节点。

反过来说,如果要插入树中有N个元素,最后会得到一个深度为L = log_2(N)平衡二叉树,所以你只需要调用你的递归算法对于log_2(N)层。在每一层,您的算法调用次数都会增加一倍,因此在您的情况下,最终会有2^log_2(N)次调用和O(2^log_2(N))运行时间。请注意2^log_2(N) = N,所以它们都是相同的,但我们会在一秒钟内获得二叉树的优势。

如果树不平衡,最终深度大于log_2(N),因此您有更多的递归调用。在极端情况下,当您的所有孩子都在父母的左侧(或右侧)时,您有N个递归调用,但每个调用都会立即从其中一个分支返回(一侧没有孩子)。因此,您将拥有O(N)运行时间,这与以前相同。每个节点都被访问过一次。

平衡树的优势在于搜索等情况。如果左手孩子总是小于父母,而右手孩子总是大于,那么你可以在n时间内在N个节点中搜索元素O(log_2(N)) (不是2^log_2(N)!)。但是,如果您的树严重失衡,则此搜索将成为所有值的线性遍历,您的搜索结果为O(N)。如果N非常大,或者您执行此搜索,那么这可能是易处理算法和难处理算法之间的差异。