二进制搜索树中按顺序遍历的复杂性(使用迭代器)

In-order traversal complexity in a binary search tree (using iterators)?

本文关键字:迭代器 复杂性 搜索树 顺序 遍历 二进制      更新时间:2023-10-16

相关问题:二叉树O(N)的无序树遍历的时间复杂性?,然而,它是基于通过递归的遍历(因此在O(log N)空间中),而迭代器只允许消耗O(1)空间。

在C++中,通常要求增加标准容器的迭代器是O(1)运算。对于大多数容器,这是微不足道的证明,然而对于map等容器,这似乎有点困难。

  • 如果map被实现为跳过列表,那么结果将是显而易见的
  • 然而,它们通常被实现为红黑树(或者至少是二进制搜索树)

因此,在按顺序遍历过程中,有时不太容易达到"下一个"值。例如,如果您指向左子树的右下叶,那么下一个要遍历的节点就是根,它离depth步之遥。

我试着"证明"算法的复杂性(以"步骤"为单位)是摊销的O(1),这似乎没问题。然而,我还没有完成演示。

这是我为一棵深度为4的树绘制的一个小图,数字(在节点的位置)表示在按顺序遍历过程中从该节点到下一个节点的步骤数:

3
2       2
1   1   1   1
1 2 1 3 1 2 1 4

注意:最右边的叶子的成本为4,以防这是一棵大树的子树

对于15个节点的总数,总和为28:因此平均每个节点的成本小于2,这(如果它成立的话)将是一个不错的摊销成本。因此:

  • 在按顺序遍历过程中,对于平衡(和完整)的二进制搜索树,递增迭代器真的是O(1)吗
  • 可以将结果扩展到非完全二进制搜索树吗

是的,对于任何树,每次迭代的摊余成本实际上是O(1)

证据是基于你"访问"每个节点的次数。
树叶只被造访一次。无树叶最多访问3次:

当从父节点转到节点本身时,
  1. 从左子树返回时
  2. 从右侧子树返回时

不再有对任何节点的访问,因此,如果我们对每个节点的访问次数求和,我们得到一个小于3n的数字,因此所有节点的访问总数加起来就是O(n),这就得到了每一步摊销的O(1)

(注意,由于在一棵完整的树中有n/2片叶子,我们得到的是你遇到的2n,我相信可以表明,对于任何树,访问量的总和都会小于2n,但这种"优化"不在IMO的范围内)。


每个步骤的最坏情况是O(h),它是平衡树中的O(logn),但在某些情况下可能是O(n)


p.S.我不知道红黑树是如何在C++中实现的,但如果树数据结构包含每个节点的parent字段,它可以替换递归堆栈并允许O(1)空间消耗。(这当然是"欺骗",因为存储n这样的字段本身就是O(n))。