每页http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx “自上而下删除”是红黑树节点移除的实现,其通过向下推动树中的红色节点来主动平衡树,使得正被移除的叶节点保证是红色的。由于叶节点保证是红色的,因此您不必担心重新平衡树,因为删除红叶节点不会违反任何规则,并且您不必执行任何其他操作即可平衡并恢复红黑。
“自下而上删除”涉及在树下进行常规二进制搜索以找到要删除的节点,在叶节点中交换(如果找到的节点不是叶节点),然后恢复红色 - 黑树属性通过攀爬树而修复红黑规则违规。
自上而下删除是否会最大限度地减少重新平衡操作的次数?自上而下的删除是否有可能主动进行过多的重新着色和重新平衡?
这种情况如何:(x)表示红色节点
8
_____/ \____
/ \
4 12
/ \ / \
2 6 10 14
/ \ / \ / \ / \
1 3 5 7 9 11 13 15
\
(16)
如果我想删除16,则自下而上的删除不会进行任何重新平衡,但是在发现不需要重新着色操作之前,自上而下的删除会一直重新着色节点:
迭代1:
(8)
_____/ \____
/ \
4 12
/ \ / \
2 6 10 14
/ \ / \ / \ / \
1 3 5 7 9 11 13 15
\
(16)
迭代2:
8
_____/ \____
/ \
(4) (12)
/ \ / \
2 6 10 14
/ \ / \ / \ / \
1 3 5 7 9 11 13 15
\
(16)
迭代3:
8
_____/ \____
/ \
(4) 12
/ \ / \
2 6 (10) (14)
/ \ / \ / \ / \
1 3 5 7 9 11 13 15
\
(16)
然后在迭代4中,您发现您不需要按下,因为16已经是红色。那么自上而下的删除更有时间和空间效率吗?
答案 0 :(得分:4)
从我收集的内容:“自上而下删除”避免在操作期间多次遍历路径中的同一节点。因此,考虑到从根到给定节点的简单路径,如果你要对那个路径中的节点做一些事情,为什么不在下行呢?它避免了不止一次遍历路径的某些部分。因此,这节省了时间。
类似的原则用于2-3-4树中的多个操作(包括插入)(a,b-tree的特殊子例)
认为,在一般情况下,确实如此。因为通过几次重新平衡操作,你可以更容易地插入一些东西。
可能,但这取决于数据集。但是,如上所述。这可以减少整体重新着色和重新平衡的次数。
答案 1 :(得分:3)
总之,是的。在eternally confuzzled处呈现的自顶向下算法不需要节点上的父指针。自下而上的算法在时间和空间之间进行权衡:在插入和删除后重新平衡时,父指针允许一些短路。
例如,红黑树的OpenJdk-7's implementation有父指针,允许它选择删除后是否需要重新平衡(例如在你的场景中)。
通常,是:自上而下的方法每次操作只能遍历一次树,而底层方法每次操作必须遍历树两次。正如我之前提到的,自下而上的方法可以通过使用父指针来缩短一些时间。但绝对不是每次都遍历整个树。
两种实现也可以选择利用threading来改进迭代整个树所需的时间或空间。这需要每个节点一两个标志的开销。这也可以使用父指针实现,但效率不高。 NB:线程链接表示线程不如父指针有效,但这仅适用于自下而上的树(本书涵盖的内容)。
回到大学时,我们在C ++中实现了eternally confuzzled's top-down red-black tree,并与我们STL(自下而上)的std :: map实现进行了比较。我们自上而下的方法肯定更快 - 我想说它在所有变异操作上都快2倍。搜索也更快,但我不能说这是由于更平衡的树还是更复杂的代码。
可悲的是,我不再拥有代码,也没有代码。