【问题标题】:Why is the space complexity of a recursive inorder traversal O(h) and not O(n)为什么递归中序遍历的空间复杂度是 O(h) 而不是 O(n)
【发布时间】:2017-05-03 06:48:59
【问题描述】:

所以我知道递归顺序遍历的空间复杂度是 O(h) 而不是 O(n),因为 h = 树高,n = 树中的节点数。

这是为什么呢?假设这是遍历的代码:

public void inorderPrint (TreeNode root) {

    if (root == null) {
        return;
    }

    inorderPrint(root.left);
    System.out.println(root.data);
    inorderPrint(root.right);

}

我们将 n 个内存地址推送到调用堆栈,因此,空间复杂度应该是 O(n)。

我错过了什么?

【问题讨论】:

  • 你不只是在推动——你在爆发。因此,堆栈的某些部分被多次使用。树的高度控制着你在弹出之前推动了多少。顺便说一句——我认为你打错了,函数不应该调用自己而不是preorderPrint吗?
  • 查看这个以获得更清晰的答案:stackoverflow.com/questions/33590205/…

标签: data-structures binary-tree traversal inorder


【解决方案1】:

地址在返回时从堆栈中删除。当从更接近根的级别进行新调用时,此空间将被重新使用。所以同时栈上的最大内存地址数就是树的高度。

【讨论】:

    【解决方案2】:

    恕我直言,您应该将空间复杂度视为O(n)。在使用大 O 表示法处理空间和时间复杂度时,我们总是尝试将复杂度值作为输入元素数量的函数,在这种情况下为 n。

    此外,如果您考虑右偏二叉树或左偏二叉树的情况,那么您会发现 O(n) 空间复杂度是合适的。看看以下右偏二叉树的例子:

      1
     / \
        2
       / \
          3
    

    节点数,n = 3

    递归遍历所需的堆栈帧数 = 3

      1
     / \
        2
       / \
          3
         / \
            4
           / \
    

    节点数,n = 4

    递归遍历所需的堆栈帧数 = 4

    因此您可以得出结论,O(n) 在这种最坏的情况下是合适的空间复杂度(w.r.t. 树结构)。在所有其他情况/类型的树中,所需的堆栈帧数总是小于n。这就是我们表达复杂性的方式。所有可能的情况所占用的实际空间应始终小于或等于所描述的函数。

    此外,在所有情况下,它始终是O(h) <= O(n)。因此,将空间复杂度视为O(n) 只是在输入元素数量方面为我们提供了一种统一的思维方式。尽管由于@StefanHaustein 在他的回答中提到的原因,O(h) 空间复杂度同样正确。

    【讨论】:

    • 这绝对取决于你的二叉树的特性。对于一般情况,是的,对于不平衡的树,最坏的情况是O(N)。但是如果你知道你的树是平衡的(例如 AVL 或红黑),那么你可以保证你的树的高度最多为Log(N),因此你的空间复杂度将为O(log N)遍历也是如此。
    【解决方案3】:

    递归的空间复杂度总是递归的高度/深度,所以按照这个一般规则,中序遍历最多可以有h个高度,其中h是从根节点到最深节点的长度。递归的空间复杂度 = O(递归树的深度)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-13
      • 1970-01-01
      • 2020-05-26
      相关资源
      最近更新 更多