在尝试修复库中的错误时,我搜索了有关在红树和黑树上找到子范围的论文,但没有成功。我正在考虑使用拉链的解决方案,以及与 不可变数据结构的删除算法上常用的追加操作类似的方法,但我仍在想是否还有我找不到的更好方法,甚至某些最低复杂度边界在这样的手术上?
明确地说,我正在谈论一种算法,给定一棵红黑树并有两个边界,它将生成一个新的红黑树,其中第一棵树的所有元素都属于这些边界。
当然,复杂度的上限是遍历一棵树并通过添加元素构造另一棵树的复杂度。
在尝试修复库中的错误时,我搜索了有关在红树和黑树上找到子范围的论文,但没有成功。我正在考虑使用拉链的解决方案,以及与 不可变数据结构的删除算法上常用的追加操作类似的方法,但我仍在想是否还有我找不到的更好方法,甚至某些最低复杂度边界在这样的手术上?
明确地说,我正在谈论一种算法,给定一棵红黑树并有两个边界,它将生成一个新的红黑树,其中第一棵树的所有元素都属于这些边界。
当然,复杂度的上限是遍历一棵树并通过添加元素构造另一棵树的复杂度。
Answers:
这个答案结合了我对问题的一些评论并加以扩展。
红黑树上的子范围运算可以在最坏情况下的O(log n)时间执行,其中n是原始树中的元素数。由于生成的树将与原始树共享某些节点,因此仅当树是不可变的(或树是可变的,但不再需要原始树)时,此方法才适用。
首先请注意,可以通过两个拆分操作来实现子范围操作。在此,分割操作采用一棵红黑树T和一个密钥x,并生成两棵树L和R,以使L包含T的所有元素小于x,R包含T的元素大于x。因此,我们现在的目标是在最坏的O(log n)时间对红黑树实施拆分操作。
我们如何在O(log n)时间内对红黑树执行拆分操作?好吧,原来有一种众所周知的方法。(我不知道,但我不是数据结构专家。)考虑联接操作,它采用两棵树L和R,使得L中的每个值都小于R中的每个值,并产生由所有树组成的树。连接操作可以在最坏情况下的时间O(| r L -r R | +1)中实现,其中r L和r R分别是L和R的等级(即,从根到每片叶子的路径上的黑色节点数)。拆分操作可以通过使用O(log n)次的联接操作来实现,并且通过考虑伸缩总和,最坏情况下的总时间仍然是O(log n)。
Tarjan的一本书[Tar83]的4.1和4.2节介绍了如何在最坏情况下的时间O(log n)上对红黑树实施联接和拆分操作。这些实现销毁了原始树,但是通过复制节点而不是对其进行修改,很容易将它们转换为不可变的功能实现。
附带说明一下,Objective Caml的Set和Map模块在(不可变的)平衡二进制搜索树上提供了分割操作以及其他标准操作。尽管它们不使用红黑树(它们使用平衡的二进制搜索树,其约束是左高度和右高度最多相差2个),但是查看它们的实现也可能有用。这是Set模块的实现。
参考文献
[Tar83] Robert Endre Tarjan。 数据结构和网络算法。CBMS-NSF应用数学区域会议系列第44卷,SIAM,1983年。
解决方案是不使用红黑树。在展开树和AVL树中,用于拆分和合并的代码非常简单。我为您提供以下带有Java代码的URL,这些URL用于支持此功能的展开树和AVL树。转到以下URL,然后检出Set.java(avl树)和SplayTree.java(splay树)。
ftp://ftp.cs.cmu.edu/usr/ftp/usr/sleator/splaying/
---丹尼·希勒(Danny Sleator)
O(n)
?我没有问过哪种树具有简单的子范围实现,因为这不是我的问题。这个答案虽然意图很好,但却是题外话,对眼前的问题毫无用处。
(这本来是评论,但我太新了,不能发表评论。)
我只想指出,您可能也对“ excision”操作感兴趣,该操作将子范围作为新树返回,而将输入树作为子树返回。但是,由于已知方法依赖级别链接,因此您需要控制树的底层表示。切除在时间上与较小的树的大小成对数关系,尽管在摊销的意义上(“摊销”为iirc,因为我已无权使用论文了),请参见:
K. Hoffman,K。Mehlhorn,P。Rosenstiehl和RE Tarjan,使用水平链接搜索树对线性时间中的Jordan序列进行排序,信息与控制,68(1986),170--184
PS:以上引用来自Seidel的海底捞文章。挖土机也支持切除术。
这适用于 。与“遍历树并插入结果”进行比较,这需要。
更新,以响应对 辅助空间:相信您需要 辅助空间可以构建几乎完整的二叉树,前提是事先告知您大小,然后您可以按一个接一个的顺序接收元素。画出完整的最后一棵树,想象一下您收到了第一棵元素。这些元素通过切一些边缘的垂直线与其他元素分开。由于这些边缘的左端需要稍后连接,因此您需要记住它们。在最坏的情况下,垂直线会切成锯齿状 边缘。
我没有弄清楚细节,所以我不确定额外的簿记如何影响运行时间。
第二次更新:JeffE在下面的评论中介绍了如何使用辅助空间并在同一时间范围内。(至少对于可变树木而言。)这意味着我的挥手论点在上面 空间是错误的。
O(logn)
,从而避免使用临时数组。