红黑树

https://www.bilibili.com/video/av45909616?from=search&seid=4110673649068381683

https://blog.csdn.net/v_july_v/article/details/6105630

http://www.tianxiaobo.com/2018/01/11/红黑树详细分析/#323-情况三

性质

  1. 每个节点非红即黑
  2. 根节点总是黑色的
  3. 如果某个节点是红色的,则它的子节点必须是黑色的(反之不一定)
  4. 每个叶子节点都是黑色的空节点(NIL节点)
  5. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)

修复违规:变色/旋转

img

插入

如果插入的节点是黑色,那么这个节点所在路径比其他路径多出一个黑色节点,这个调整起来会比较麻烦。如果插入的节点是红色,此时所有路径上的黑色节点数量不变,仅可能会出现两个连续的红色节点的情况。这种情况下,通过变色和旋转进行调整即可,比之前的简单多了。

以红色为默认插入

  • 如果父节点是黑色,没有影响
  • 如果父节点是红色,那么就破环了一个红色节点的孩子节点是黑色的性质,需要进行旋转和染色让这条路径上的黑色节点数保持不变。也可能黑色节点数量整体加一
  1. 叔叔节点也为红色。
    1. 变色即可
  2. 当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子
    1. 左旋
  3. 当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左孩子
    1. 父节点和祖父节点变色,以祖父节点右旋
image

删除

删除修复操作在遇到被删除的节点是红色节点或者到达root节点时,修复操作完毕。

删除修复操作是针对删除黑色节点才有的,当黑色节点被删除后会让整个树不符合RBTree的定义的第四条。需要做的处理是从兄弟节点上借调黑色的节点过来,如果兄弟节点没有黑节点可以借调的话,就只能往上追溯,将每一级的黑节点数减去一个,使得整棵树符合红黑树的定义。

  1. 节点是红色或黑色。
  2. 根是黑色。
  3. 所有叶子都是黑色(叶子是NIL节点)。
  4. 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
  5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点(简称黑高)。

这个时候性质4和性质5用途就凸显了,有了这两个性质作为约束,即可保证任意节点到其每个叶子节点路径最长不会超过最短路径的2倍。

当某条路径最短时,这条路径必然都是由黑色节点构成。当某条路径长度最长时,这条路径必然是由红色和黑色节点相间构成(性质4限定了不能出现两个连续的红色节点)。而性质5又限定了从任一节点到其每个叶子节点的所有路径必须包含相同数量的黑色节点。此时,在路径最长的情况下,路径上红色节点数量 = 黑色节点数量。该路径长度为两倍黑色节点数量,也就是最短路径长度的2倍。

左旋是将某个节点旋转为其右孩子的左孩子,而右旋是节点旋转为其左孩子的右孩子

上面五种情况中,情况一和情况二比较简单,情况三、四、五稍复杂。但如果细心观察,会发现这三种情况的区别在于叔叔节点的颜色,如果叔叔节点为红色,直接变色即可。如果叔叔节点为黑色,则需要选选择,再交换颜色。

image

删除

除操作首先要确定待删除节点有几个孩子,如果有两个孩子,不能直接删除该节点。而是要先找到该节点的前驱(该节点左子树中最大的节点)或者后继(该节点右子树中最小的节点),然后将前驱或者后继的值复制到要删除的节点中,最后再将前驱或后继删除。由于前驱和后继至多只有一个孩子节点,这样我们就把原来要删除的节点有两个孩子的问题转化为只有一个孩子节点的问题

红黑树删除操作的复杂度在于删除节点的颜色

  • 当删除的节点是红色时,直接拿其孩子节点补空位即可
  • 当删除的节点是黑色时,破坏了性质5。
    • 如果该节点的孩子为红色,直接拿孩子节点替换被删除的节点,并将孩子节点染成黑色,即可恢复性质5。
    • 但如果孩子节点为黑色,处理起来就要复杂的多。分为6种情况,下面会展开说明。

AVL树和红黑树的区别

  1. 插入都是最多只需要2次旋转操作,即两者都是O(1)
  2. 删除node,最坏情况下AVL需要维护从被删node到根节点路径上所有node的平衡性,因此需要旋转的量级O(logN),而RB-Tree最多只需3次旋转,只需要O(1)的复杂度。
  3. AVL查找效率更高
  4. map的实现只是折衷了两者在search、insert以及delete下的效率。总体来说,RB-tree的统计性能是高于AVL的。

你可能感兴趣的:(红黑树)