二叉搜索树进阶之红黑树
前言:
在上文我们已经学习了AVL树的相关知识以及涉及的四种旋转的内容,但是AVL树追求平衡导致旋转操作过多,一些情况下影响性能,由此我们就来了解一下二叉搜索树的另外一个分支,红黑树。
(倘若对旋转知识不了解的可以先移步:http://t.csdnimg.cn/waigV)
红黑树的概念:
红黑树是一种二叉搜索树,通过对每个节点增加一个存储位表示节点的颜色,(红色或者黑色),再通过对任何一条从根到叶子的路径的各个节点的着色方式进行限制,从而保证没有一条路径会比其他路径长出两倍,从而确保诸多基本操作例如插入删除和查找的时间复杂度始终O(logn)。
红黑树被广泛运用道许多计算机科学领域,比如C++的stl库的map与set容器的底层实现,java的TreeMap与TreeSet也采用了红黑树。
红黑树的性质:
1.
每个结点不是红色就是黑色
2.
根节点是黑色的
3.
如果一个节点是红色的,则它的两个孩子结点是黑色的
4.
对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
5.
每个叶子结点都是黑色的
(
此处的叶子结点指的是空结点)
只要满足上面五种条件,就能保证没有一条路径会比其他路径长出两倍,确保了红黑树不会变得过于不平衡,从而保证了高效的操作。
红黑树的性质的平衡:
红黑树是否进行旋转主要是依据他的叔叔节点进行判断的,以红黑树的插入操作为例,当我们在叶子处插入新节点时,要把它的默认颜色设置为红色,然后对比他的父节点颜色是否为红,为红色就要进行一系列的检查,为黑,就不用进行检查。
通常我们面临的需要选择的情况是这样的:
cur为我们新插入的节点,此时他的父亲节点parent的颜色也为红,于是找到父亲的父亲节点pparent,随后判断parent是pparent的左节点还是右节点,随后就能找到叔叔节点uncle。重要的就来了,当此时叔叔节点也为红色时,我们就可以把parent与叔叔的颜色更改为黑色,随后把爷爷节点颜色改为红色。在这种情况下,我们就不用对红黑树进行任何旋转,但是由于我们更改了爷爷节点的颜色为红色,所以我们要继续对爷爷进点进行又一次的判断。
由此可见,cur的位置其实不一定为新插入的节点,也可能时一路调整上来的节点:
比如这张图来看,最底下的节点为新增,此时我们就要把a,b颜色更改为黑,把cur颜色更改为红,此时cur与parent的眼色都为红,违反了规则,所以要继续进行判断。
总之,当我们检查到叔叔节点的颜色为红色,跟父亲一样时,就不需要进行旋转,只需要更改颜色就行。
但是如果叔叔节点为黑色或者叔叔节点不存在时,单纯进行颜色的更改已经不能满足我们的红黑树的五大规则了,所以只能进行旋转了。
叔叔存在但是为黑色:
此时只能对爷爷节点进行旋转,以图片的情况为例,就是对爷爷节点进行右单旋,然后交换爷爷节点与父亲节点的颜色就可以了。
这种情况自然也是进行左单旋。
那么什么时候进行双旋呢?
对于红黑树来说,当父亲节点时爷爷节点的左节点时,cur节点是父亲节点的右节点,就可以进行左右双旋操作。或者当父亲节点时爷爷节点的右节点,cur是父亲节点的左节点,就对爷爷节点进行右左双旋操作来保持红黑树的性质。
红黑树的优缺点
优点:
- 红黑树的插入、删除和查找操作的时间复杂度始终为 O(logn)O(\log n)O(logn),适合频繁插入和删除的动态数据集。
- 红黑树能够保持相对较好的平衡,避免了极端情况下的退化。
缺点:
- 相对于 AVL 树,红黑树的平衡程度稍差,这意味着查找操作的性能在某些情况下可能不如 AVL 树。
- 实现红黑树比其他二叉搜索树(如普通的二叉搜索树或 AVL 树)要复杂得多。
结语
红黑树在计算机科学中有着广泛的应用,尤其是在需要频繁插入和删除操作的数据结构中。虽然其实现较为复杂,但红黑树通过严格的平衡规则和旋转操作,能够提供稳定、高效的性能表现,是一种非常重要的自平衡二叉搜索树。了解红黑树的基本性质和操作过程,对于深入理解高级数据结构以及其在实际应用中的优化是非常有帮助的。
希望本文对您有所帮助!!