红色和黑色树的子范围


14

在尝试修复库中的错误时,我搜索了有关在红树和黑树上找到子范围的论文,但没有成功。我正在考虑使用拉链的解决方案,以及与 不可变数据结构的删除算法上常用的追加操作类似的方法,但我仍在想是否还有我找不到的更好方法,甚至某些最低复杂度边界在这样的手术上?

明确地说,我正在谈论一种算法,给定一棵红黑树并有两个边界,它将生成一个新的红黑树,其中第一棵树的所有元素都属于这些边界。

当然,复杂度的上限是遍历一棵树并通过添加元素构造另一棵树的复杂度。


3
@Radu:评论编辑功能中存在错误。如果在评论和编辑注释使用的乳胶,你看到奇怪的行为,如重复数据删除等
阿耶波多

@Radu我添加了两个段落以更好地解释我的问题。
Daniel C. Sobral

树木是一成不变的吗?
伊藤刚(Tsuyoshi Ito)2010年

另外,您是在上一段中指的是上限,而不是下限吗?
伊藤刚(Tsuyoshi Ito)2010年

2
似乎可以在最坏情况下的时间O(log n)上实现对红黑树的拆分操作,其中n是树中元素的数量。可以在ESA 2006的GerthStøltingBrodal,Christos Makris和Kostas Tsichlas撰写的论文“纯功能最坏情况下恒定时间可连续排序的列表”中找到该要求:cs.au.dk/~gerth/pub/esa06trees.html。正如我在之前的评论中提到的那样,这允许子范围操作的最坏情况O(log n)时间实现。
伊藤刚(Tsuyoshi Ito)2010年

Answers:


10

这个答案结合了我对问题的一些评论并加以扩展。

红黑树上的子范围运算可以在最坏情况下的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年。


@Radu GRIGore:是的,除非我错过了一些东西。
伊藤刚(Tsuyoshi Ito)2010年

@Radu GRIGore:也许不是,现在我不确定。split操作的这种实现为输出树分配O(log n)个新节点,但是我认为整个操作可能可以以尾递归的方式实现,只需要O(1)工作空间。如果这是正确的话,那么问题的答案将取决于您所说的“额外空间”。
伊藤刚(Tsuyoshi Ito)2010年

@Radu GRIGore:在那种情况下,我认为多余的空间是O(1),尽管我没有仔细检查它。
伊藤刚(Tsuyoshi Ito)2010年

@Radu GRIGore:我看不到为什么人们关心工作空间的数量而不关心存储结果本身所需的空间的原因。在复杂性理论中,问题通常指定结果是什么,因此存储结果所需的空间不取决于算法。但是,在当前问题中,有许多方法可以实现所需的操作,并且某些实现需要比其他实现更多的空间来存储结果。如果您忽略此空间量的差异,那么我看不到您为什么在乎我们需要多少工作空间。
伊藤刚(Tsuyoshi Ito)2010年

不可变树的问题与可变树的问题不同。我了解其中的区别,所以我对此无话可问。现在,放大两个问题之一,需要讨论两个方面:内存和时间。您没有说要使用多少内存,对我来说似乎不知道答案是什么,所以我问。我看不出这是如何使您认为我忽略了两个问题之间的区别。
Radu GRIGore

8

解决方案是不使用红黑树。在展开树和AVL树中,用于拆分和合并的代码非常简单。我为您提供以下带有Java代码的URL,这些URL用于支持此功能的展开树和AVL树。转到以下URL,然后检出Set.java(avl树)和SplayTree.java(splay树)。

ftp://ftp.cs.cmu.edu/usr/ftp/usr/sleator/splaying/

---丹尼·希勒(Danny Sleator)


5
欢迎来到该网站,丹尼!
Suresh Venkat

2
这将如何帮助修改Scala Red Black实施以支持小于的范围O(n)?我没有问过哪种树具有简单的子范围实现,因为这不是我的问题。这个答案虽然意图很好,但却是题外话,对眼前的问题毫无用处。
Daniel C. Sobral

6

(这本来是评论,但我太新了,不能发表评论。)

我只想指出,您可能也对“ excision”操作感兴趣,该操作将子范围作为新树返回,而将输入树作为子树返回。但是,由于已知方法依赖级别链接,因此您需要控制树的底层表示。切除在时间上与较小的树的大小成对数关系,尽管在摊销的意义上(“摊销”为iirc,因为我已无权使用论文了),请参见:

K. Hoffman,K。Mehlhorn,P。Rosenstiehl和RE Tarjan,使用水平链接搜索树对线性时间中的Jordan序列进行排序,信息与控制,68(1986),170--184

PS:以上引用来自Seidel的海底捞文章。挖土机也支持切除术。


此方法假定一个人已经具有指向两个边界的指针(或“手指”)。
jbapple

3

ñ[一种b]

  1. Ølgñ一种一种的后继)。
  2. 从那里开始,有序遍历将使用所需元素构建一个数组 Ø 时间。
  3. 构建一个二叉搜索树:数组的中间给出了根,然后您就可以左右递归了。叶子到根的距离最多相差一:将“远处”的叶子涂成红色。(您可以在构造树的递归过程中进行着色。)这需要Ø

这适用于 Ø+lgñ。与“遍历树并插入结果”进行比较,这需要Øñ+lg

更新,以响应对Ø 辅助空间:相信您需要 Ωlg辅助空间可以构建几乎完整的二叉树,前提是事先告知您大小,然后您可以按一个接一个的顺序接收元素。画出完整的最后一棵树,想象一下您收到了第一棵ķ元素。这些元素通过切一些边缘的垂直线与其他元素分开。由于这些边缘的左端需要稍后连接,因此您需要记住它们。在最坏的情况下,垂直线会切成锯齿状lg 边缘。

我没有弄清楚细节,所以我不确定额外的簿记如何影响运行时间。

第二次更新:JeffE在下面的评论中介绍了如何使用Ø1个辅助空间并在同一时间范围内。(至少对于可变树木而言。)这意味着我的挥手论点在上面Ωlg 空间是错误的。


考虑到这一点,我认为我可以对进行粗略的估算O(logn),从而避免使用临时数组。
Daniel C. Sobral

您可以通过在子树的根中存储子树大小来获得O(lg n)中的计数。
Radu GRIGore 2010年

...但是在节点中存储大小违反了不使用辅助空间的要求,因此我的观察并没有解决您对内存的关注。
Radu GRIGore 2010年

1
二叉树可以用唯一不变的额外空间(除了树本身)完美地重新平衡:eecs.umich.edu/~qstout/abs/CACM86.html
Jeffε

@JeffE:我实际上看了一下那篇论文,但我(愚蠢地)认为'vine'是我的数组。因此,总而言之,如果在链接的文件中将我的数组替换为“ vine”,将我的第3步替换为vine_to_tree,则会得到Ø+lgñ 时间和 Ø1个辅助空间。谢谢!
Radu GRIGore 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.