一个喜欢学习和热爱提问的人总有一种尿性,那就是当我们接触到了一个新东西的时候,肯定首先要问第一个问题:“这个究竟是什么?”。。。那么我们今天就来提出第一个问题:“什么是红黑树?”
一说红黑树必然就和算法联系起来,一说算法很多人马上就想起来当年那个子子孙孙无穷匮也的二叉树,那么二叉树、二叉查找树和红黑树有关系吗?要是有的话是什么关系?我们怎么理清楚他们呢?当然了,这个不是我们今天研究的范畴,如果你喜欢深入探讨的话,欢迎大家接着关注《老荒带你学数据结构》系列的后续文章,那么我们今天别的不谈就说红黑树。好开始!!!
PS.现在假设你知道什么是二叉树,什么是二叉查找树!!!
如果你忘了,或者你不知道的话,那么我们这里说明一下:
二叉查找树(英语:Binary Search Tree),也称为二叉搜索树、有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树模型:
那么那几个特点呢?
- 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
- 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点。
看下图,这就是一个标准的二叉查找树模型:
通过上面的图,是不是很好的证明了我们上面那四个特点。别着急咱们接着说啊!
大家看到了吧!我们不难发现他的优点:二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、重集、关联数组等。
说的在通俗点,比如说我想找12,我们是不是只要去以9为根的右子树下找就可以了呢?对吧!
那么插入一个值不也是这个原理吗,只要插入到那个区间上不就可以了,那么就说方不方便,简不简单就得了!但是,这个世界上可没有完美的事情,大家想一下要是出现了这样一种情况该咋办?
看下图,现在假设我们有一个节点8(我喜欢8!)
然后我们往他的右边一个劲的插入!!!
看到了吧,看到了吧,这熟悉的样子和这风骚的走位。这样我们的二叉查找树是不是一下子就尴尬了,那么他的问题究竟出在哪里,其实就是出在二叉(binary)而不是平衡(banlance)这个2B上。
那我们就这么跪了吗?当然不是,人类最伟大的地方就是当出现问题的时候,我们会去想解决问题的方法,而不是像蜜獾一样就是干,也不会像翻车鱼一样动不动把自己干掉。
红黑树闪亮登场。
红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
- 节点是红色或黑色。
- 根是黑色。
- 所有叶子都是黑色(叶子是NIL节点)。
- 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
- 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
那么我们闭上眼睛想想他是什么样!!!
没错他就这个样!那么他这个样体现出最大的特点是啥?你们能看出来吗?能看出来吗?看出来吗?出来吗?来吗?吗?
真相只有一个,那就是---平衡。
我们其实应该在最前面的那个概念之前再补上一句:红黑树(英语:Red–black tree)是一种自平衡二叉查找树。
他虽然定义的很繁琐,但是正是有了这种繁琐,才保证了红黑树的性能和他的查询速度。
那么我们举个例子:
1.向原红黑树插入值为14的新节点:
由于父节点15是黑色节点,因此这种情况并不会破坏红黑树的规则,无需做任何调整。
2.向原红黑树插入值为21的新节点:
由于父节点22是红色节点,因此这种情况打破了红黑树的规则4(每个红色节点的两个子节点都是黑色),必须进行调整,使之重新符合红黑树的规则。
那么我们此时必须需要变色:
为了重新符合红黑树的规则,尝试把红色节点变为黑色,或者把黑色节点变为红色。
下图所表示的是红黑树的一部分,需要注意节点25并非根节点。因为节点21和节点22连续出现了红色,不符合规则4,所以把节点22从红色变成黑色:
但这样并不算完成整个过程,因为我们又多出的那个黑色节点又打破了规则5,所以发生连锁反应,需要继续把节点25从黑色变成红色:
看没看到,看没看到,变颜色了吧!
但是到这就完了吗?不!如果你是个聪明的孩子或者你的视力是完好无损的,那么你马上就发现25和27,真是要把人逼疯了是不是!
接着变:
这次终于完成了。对吧?
很遗憾的告诉你!还没有,因为25上面还有一个17那,哇哈哈哈哈接着来吧!但是我们接着变之前,来学习两个原理!
那么这都是什么原理呢?其实这是左旋转和右旋转原理。
左旋转:
逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子。说起来很怪异,大家看下图:
图中,身为右孩子的Y取代了X的位置,而X变成了自己的左孩子。
右旋转:
顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子。大家看下图:
图中,身为左孩子的Y取代了X的位置,而X变成了自己的右孩子。
那么这有什么用呢?
刚才我们是不是插入一个21来着!
然后变成了这个样子
然后你看17-25是不是红-红。那么我们现在是不是变色已经无法彻底解决了。那咋整啊,那就转圈圈呗。“爱的魔力转圈圈。。。”
我们把节点13看做X,把节点17看做Y,像刚才的示意图那样进行左旋转:
然后就。。。
这样了。
但是由于根节点必须是黑色节点,所以必须要变色,又变色,啊~~~~~~~~~~~~~~~~~~~~~~~~~~~
但是还是没有结束。。。。
因为其中两条路径(17 -> 8 -> 6 -> NIL)的黑色节点个数是4,其他路径的黑色节点个数是3,不符合规则5。
这时候我们需要把节点13看做X,节点8看做Y,像刚才的示意图那样进行右旋转:
最后根据规则来进行变色:
最后我们的红黑树终于符合规则了。这一个例子的调整过程比较复杂,经历了如下步骤:
变色 -> 左旋转 -> 变色 -> 右旋转 -> 变色
好了,大家还是冷静一下吧,我拿出了我的校园小中华---红塔山。默默的点了一根,顺便怀念一下我逝去的青春。
大家要想知道更多关于红黑树的内容,请自行百度或者维基百科或者谷歌或者问我或者买书或者问老师或者。。。。。。。
最后一句话:JDK1.8 HASHMAP 里面就有红黑树~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~谢谢大家晚安!!!!!!