大家好,我是“Stephen·谢”,之前提出的索引优化数据库查询的文章中提到了树(Tree)的概念,由于树结构的强大性和重要性,有必要在接下来的几篇文章中对几种重要的树结构以通俗易懂的方式做一下演示图解。
二叉查找树:
首先,我们来了解一下二叉查找树,二叉查找树具备以下几个特点:
1、左子树上所有节点的值均小于或等于它的根节点的值;
2、右子树上所有节点的值均大于或等于它的根节点的值;
3、左右子树也分别为二叉排序树。
下面我们以一棵典型的二叉查找树来查找值为10的节点:
1、首先查看根节点9 2、由于10大于9,因此查看右孩子13 3、由于10小于13,因此查看左孩子11 4、由于10小于11,因此查看左孩子10,发现正好是要查找的节点以上图例正是典型的二分查找的思想,查找所需的最大次数等同于二叉查找树的高度。在往树中插入新节点的时候也要用类似的方法,通过一层一层地比较大小从而找到新节点适合插入的位置。但是即便如此,二叉查找树依旧存在它的缺陷,并且此缺陷恰恰体现在插入新节点的时候。请看下面图例展示:
假设初始二叉查找树只有三个节点,根节点9,左孩子8,右孩子12 我们依次插入7,6,5,4,3这五个节点,依照二叉查找树特性,会变成上面样子这样的瘸腿形态虽然也符合二叉查找树的特性,但是查找的性能却大打折扣,几乎变成了线性数据结构。为了解决二叉查找树多次插入新节点而导致的不平衡问题,红黑树便应运而生了。
红黑树:
红黑树是一种自平衡的二叉查找树,除了符合二叉查找树的特性外,还具有下列性质:
1、根节点是黑色,节点是红色或黑色;
2、每个叶子节点都是黑的空节点;(nil节点)
3、每个红色节点的两个子节点都是黑色;(也就是说从每个叶子到根的所有路径上不能有两个连续的红色节点)
4、从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
这就是一棵典型的红黑树这些规则的限制,保证了红黑树的平衡,红黑树从根到叶子的最长路径不会超过最短路径的两倍。当红黑树插入或者删除节点的时候,红黑树的规则可能被打破,这时候就需要做出调整来维持它的平衡了。请看下面的例子(注意:新插入的节点必须是红色,否则就没有意义了):
向原红黑树中插入值为14的新节点 向原红黑树中插入值为21的新节点由于父节点22是也是红色节点,因此打破了红黑树的规则(每个红黑树的两个子节点都是黑色),所以必须进行调整,使之重新符合规则。那么我们需要作出怎样的调整才能保证一棵红黑树始终是符合规则的标准红黑树呢?调整有两种方法:“变色”和“旋转”,其中,旋转又分为两种形式:“左旋转”和“右旋转”。
变色,左旋转和右旋转:
我们先看变色:
为了重新符合红黑树的规则,尝试把红色节点变成黑色,或者把黑色节点变成红色。
下图是摘自上面红黑树的一部分,节点25并非根节点。正如上面所说因为新节点21和节点22连续出现了红色,不符合规则,所以把节点22从红色变成黑色。
将节点22从红色变成黑色但这样并不算完,节点22变成黑色后,凭空多出的黑色节点又打破了规则,发生连锁反应,需要继续把节点25从黑色变为红色。
将节点25从黑色变成红色此时仍未结束,节点25变为红色后,又和节点27形成了两个连续的红色,规则又被打破,需要继续把节点27从红色变为黑色。
将节点27从红色变成黑色如此一路走下来,完成变色调整。
再看一下左旋转:
逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为左孩子。
身为右孩子的Y取代了X的位置,而X变成了左孩子再看一下右旋转:
顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为右孩子。
身为左孩子的Y取代了X的位置,而X变成了右孩子综合变色和旋转方法的案例演示:
这几种方法究竟怎么使用呢?红黑树的插入和删除包含很多种情况,每种情况都有不同的处理方式,下面举一个典型的例子,可以体会一下这个过程。
还以刚才插入节点21为例:
插入节点21首先我们变色处理,把节点25及其下方的节点变色:
虚线框中就是上文变色部分所讲到的此时节点17和节点25是连续的两个红色节点,那么此时再把节点17变成黑色节点可以吗?显然是不可以的,这样依然不符合规则,更不可以把根节点13变成红色。
既然变色已经无法解决问题,我们此时就要使用旋转了,我们把节点13看作X,把节点17看作Y,进行左旋转:
左旋转1 左旋转2 左旋转3旋转完成后,由于根节点必须是黑色,所以还需要进行变色:
再将根节点变色至此并没有结束,因为其中两条路径(17->8->6->NIL)的黑色节点数是4,其他路径的黑色节点数是3,依旧不符合规则。这时我们需要把节点13看成X,节点8看成Y,做右旋转:
右旋转1 右旋转2 右旋转3然后再进行变色:
最终变色经过上面一系列的调整,我们的红黑树终于变得重新符合规则,整个过程有点复杂,经历了:变色-->左旋转-->变色-->右旋转-->变色这样的一系列步骤。
总结:
经过上面细致的步骤演示,想必大家对二叉查找树和红黑树有所了解了吧,对红黑树结构插入新节点所触发的一系列的变化流程也有了大概印象。实际中红黑树的应用是很多的,比如JDK(Java开发工具包)的集合类TreeMap和TreeSet底层就是红黑树实现的,在Java8中,HashMap也用到了红黑树。其实关于红黑树自平衡的调整,插入和删除节点时涉及到的情形一一展开讲解还是很多很多的,但是万变不离其中,红黑树自平衡调整的主体思想都是上面所叙述的,大家有兴趣可以再进行深入的探究。
网友评论