前言
按照正常的逻辑介绍完List之后应该开始Set会不会有大佬认为我乱了,胡来?但是,我们阐述Set时我们必须先阐述HashMap,否则不方便阐述HashSet。所以我准备把Map提到Set之前,Map首先就是HashMap,而在Java8版本中HashMap是由数组+链表+红黑树。如果不了解红黑树,就无法进行下去,所以我抽一个单独的出来说一下,也是由于最近用了红黑树,所以比较熟悉,拿出来说说,有错的话求求大佬指导指导。
一、二叉查找树
要了解红黑树,我们首先来了解一下二叉查找树(Binary Seach Tree),简称:BST
二叉查找树特性:
1.左子树上所有结点值均小于或者等于它根结点的值;
2.右子树上所有结点的值均大于或等于它根结点的值;
3.左右子树也分别为二叉排序树。
这么说可能不清楚,举个例子吧:
可能看不出什么特别,那我们来查找一下值为10这个结点:
①首先,得到根结点,由于 10>9 ,所以进入右子树
②10<13 ,所以进入13结点的左子树
③10<11 ,所以进入11结点的右子树
④10=10 ===>找到了
这个思想来源于二分查找,查找的最大次数等于二叉树的高度,插入结点也同样可以利用此方法一个一个插入。
但是这个有缺陷:
比如:
如果我们插入:7、6、5、4、3
此时二叉树也符合二叉查找树,但是如此的话我们再来查找4或者3其性能就变得和线性结构一样了。
个人推论:从线性列表中二分查找法找中间值,得到启发,能否重新给二叉查找树定一个结点来用呢?红黑树自此正式登场。
二、红黑树
什么是红黑树呢?
红黑树全称:Red Black Tree,他有这些特性:
1.结点时红色或者黑色
2.根结点是黑色
3.每个叶子结点都是黑点的空结点(NIL)
4.每个红色结点的两个子节点都是黑色(从每个叶子结点到根的所有路径上不能有连续两个的红色结点)
5.从任一结点到其每个叶子结点的所有路径都包含相同数目的黑色结点。
举个栗子1:
红黑树的规则虽然很多,但是正是由于这些规则,保证了红黑树的自平衡。红黑树从根到叶子结点的最长路径不会超过最短路径的2倍。当插入或者删除结点时有可能打破规则。所以我们需调整(调整方法:变色、旋转–左旋转、右旋转)。
举个栗子2:
往例子1中添加值为21的新结点
由于22是红色,所以该树打破了规则4,必须调整,使之符合
调整方法:变色、旋转(左旋转,右旋转)
变色:为了重新符合红黑树规则,尝试把红色变为黑色结点,或者把黑色变为红色。
例子:用例子2中的树的一部分子树,注意:25并非根结点。因为21和22都为红色,不符合规则4,所以把22由红变黑
但是这样凭空出现了黑色又打破了规则5,所以把25由黑变红
但这样,25与27之间形成了连续红结点,所以把27由红变黑
左旋转:逆时针旋转红黑树两个结点,使父节点被右孩子取代,而自己成为左孩子
例子:
右旋转:顺时针旋转红黑树结点使父节点被左孩子取代,而自己成为右孩子。
接着之前的变色我们回到整个红黑树
我们可以看到17和25之间又有连续的红色,这个时候变色已经解决不了了,我们把13和17进行左旋转,得到:
因为根结点为黑色,所以进行变色
但由于(17-8-6-NIL)黑结点4个,其他3个黑结点,不符合规则5,所以我们把13和8右旋转。
根据变色规则:
过程:变色–左旋–变色–右旋–变色
总结
以上就是红黑树的内容,如果没看懂的可以自己在图上画一画。然后补充一下知识点:
左旋:当前父为红,叔为黑,当前为左子树。
右旋:当前父为红,叔为黑,当前为右子树。
(实际应用上作用并不大,但是有时候需要给别人解释的时候需要这么说。)