红黑树-平衡二叉搜索树
二叉搜索树的缺陷
- 当插入连续的数据时,如key为9,8,7,6,5或1,2,3,4,5等,二叉搜索树会很不平衡,会极大影响树结构查找、插入的效率。直接由O(logN)下降为O(N).
- 一般会选择AVL树或者红黑树来保持树的平衡,并且红黑树在插入、删除等操作的性能要优于AVL树。
红黑树的规则
-
红黑树除了符合二叉搜索树的基本规则外,还符合以下性质:
- 节点是红色或者黑色
- 根节点是黑色
- 每个叶子节点都是黑色的空节点(NIL节点)
- 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
红黑树的相对平衡
- 从根到叶子的最长可能路径,不会超过最短可能路径的两倍长
- 结果就是这个树基本是平衡的虽然没有做到绝对的平衡,但是可以保证在最坏的情况下,依然是高效的
- 为什么可以做到最长的路径不超过最短路径的两倍长
- 性质4决定了路径不能有两个相连的红色节点
- 最短的可能路径都是黑色节点
- 最长的可能路径都是黑色和红色交替
- 性质5所有路径都有相同数目的黑色节点
- 这就表明了没有路径能多余其他路径的两倍长
保持平衡的方法
插入一个新节点时,有可能树不再平衡,可以通过三种方式的变换,让树保持平衡
- 变色
- 为了重新符合红黑树的规则,尝试把红色节点变为黑色、或者把黑色节点变为红色
- 首先,插入的新的节点通常是红色节点。因为在插入节点为红色的时候,有可能插入依次是不违反红黑树任何规则,而插入黑色节点,必然会导致有一条路径上多了黑色节点,这是很难调整的
- 红色节点可能导致出现红红相连的情况,但是这种情况可以通过颜色变换和旋转来调整
- 左旋转
- 逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子
- 它们有子树是否会影响旋转? 答:不会
- 右旋转
- 顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子
- 它们有子树是否会影响旋转?答:不会
插入操作的情况分析
首先插入的新节点默认为红色,N代表插入节点Node,P代表N的父节点ParentNode,U代表N的叔节点UncleNode,G代表N的祖父节点GrandeParentNode。
- 情况一
- 现象:新节点N位于树的根上,没有父节点
- 做法:这种情况下,我们直接将红色变为黑色即可,这样满足性质2
- 情况二
- 现象:新节点的父节点P是黑色
- 做法:性质四没有失效(新节点是红色的),性质5也没有人和问题。尽管新节点N有两个黑色的叶子节点NIL,但是新节点N是红色的,所以通过它的路径中黑色节点的个数依然相同,满足性质5。所以直接插入就可以。
- 情况三
-
现象:P为红色,U也是红色,G为黑色。
-
做法:改变为 P黑,U黑,G红
-
可能出现的问题:(1)G的父节点也可能是红色,这就违反了性质3,可以递归地调整颜色。(2)如果递归调整颜色到了根节点,就需要进行旋转了(见后例)
-
- 情况四
- 现象:父红,叔黑,祖黑,N是左儿子
- 做法:变成父黑祖红,进行右旋转,(先变色再旋转)
- 情况五
-
现象:父红,叔黑,祖黑,且N是右儿子
-
做法:先以P为根进行左旋转,将P作为新插入的红色节点考虑即可,此时同情况四,将自己变成黑色,祖父变成红色,以祖为根进行左旋转
-
插入数据案例
将10,9,8,7,6,5,4,3,2,1依次插入红黑树,过程示意图如下:
参考coderwhy老师的数据结构