首先手撸红黑树,需要明白红黑树是什么东西?
FBI警告:
千万不要去看源码去理解红黑树!
千万不要去看源码去理解红黑树!
千万不要去看源码去理解红黑树!(重要的事情说三遍,因为你会懵逼的,除非你是大神!!!)
其实红黑树其底层就是(特殊的,只是类似自平衡)二叉查找树.就是这么简单
很多人懵逼就是不知道其底层结构.
网上很多教程提到的情况
可能有同学会问,什么是二叉查找树?什么是平衡树?对于这两个有疑问的同学,可以看下我往期的博客
30分钟看完数据结构和算法原理
首先要明白 红黑树五条性质:
性质一:节点是红色或者是黑色;
在树里面的节点不是红色的就是黑色的,没有其他颜色,要不怎么叫红黑树呢,是吧。
性质二:根节点是黑色;
根节点总是黑色的。它不能为红。
性质三:每个叶节点(NIL或空节点)是黑色;
这个图片就是一个红黑树,NIL节点是个空节点,并且是黑色的。
性质四:每个红色节点的两个子节点都是黑色的(也就是说不存在两个连续的红色节点,黑色的可以连在一起);
就是连续的两个节点不能是连续的红色,连续的两个节点的意思就是父节点与子节点不能是连续的红色。
性质五:从任一节点到其没个叶节点的所有路径都包含相同数目的黑色节点;
下面的图从根节点到每一个NIL节点的路径中,都包含了相同数量的黑色节点。
这五条性质约束了红黑树,可以通过数学证明来证明,满足这五条性质的二叉树可以将查找删除维持在对数时间内。
当我们进行插入或者删除操作时所作的一切操作都是为了调整树使之符合这五条性质。
下面我们先介绍两个基本操作,旋转。
旋转的目的是将节点多的一支出让节点给另一个节点少的一支,旋转操作在插入和删除操作中经常会用到,所以要熟记。
什么是左旋?左旋就是将当前要旋转的点进行逆时钟转90度,然后把要旋转的点(未旋转之前)的右节点的左子树节点挂到要旋转的点(已经旋转完毕)的右子树节点
好懵逼啊!!!不着急用一个动画了解
左旋图:
右旋恰好相反
右旋图:
接下来讲插入:
首先一个节点要插进来,颜色默认红色,根据节点的大小,想按照二叉查找树的规则插到相应的位置.
然后就要进行颜色变换了
变换规则如下
(下面这段话非常重要,一定要看完)
首先我们要明白有几种情况需要注意一下(新插入的节点默认为红色!)
1.如果是插入到根节点,直接改为黑色即可
2.如果插入的的父节点是黑色,直接插入即可
3.出现双红,也就是如果插入的节点的父节点是红色.通俗讲就是有两个红色的节点连在一起了.
这里面分两种情况.
(1).如果插入的节点的父节点的兄弟(叔叔节点)如果都是红色,就直接改颜色. 把父节点和叔叔节点改为黑色,把爷爷节点改为红色.
(2)如果插入的节点的父节点的兄弟(叔叔节点)如果是黑色,下面要分两种情况
A.如果插入的节点的父节点是爷爷节点左子树
如果当前节点作为父节点的右子树,则进行左旋
怎么左旋:左旋之前,当前指针移动到当前节点的父节点
如果当前节点作为父节点的左子树,则进行右旋
怎么右旋:右旋之前,当前指针移动到当前节点的爷爷节点,然后把父节点改为黑色,爷爷节点改为红色
B.如果插入的节点的父节点是爷爷节点右子树(这点很重要,网上的教程几乎没讲,自己摸索出来的)
如果当前节点作为父节点的右子树,则进行左旋(这里跟上面情况一样)
怎么左旋:左旋之前,当前指针移动到当前节点的爷爷节点,然后把父节点改为黑色,爷爷节点改为红色
如果当前节点作为父节点的左子树,则进行右旋(这里跟上面情况一样)
怎么右旋:右旋之前,当前指针移动到当前节点的父节点
又是好懵逼啊?!!!!
别着急用一个例子分析
首先我已经有了一个红黑树,现在有一个节点6想往里面插(我承认我没有开车),先根据二叉查找树的规则插到相应的位置,如下图
然后插完你会发现6 和7 颜色一样,连在一起了,破坏了红黑树的规则了(有毒.......)
出现这种问题,只能进行接下来的颜色变换了(根据3.1规则)
首先当前节点6 的父亲7变为黑色
再把当前节点6 的叔叔13变为黑色
再把当前节点6 的爷爷12变为红色
然后再把指针移到12这个节点(也就是当前节点变成12了)
如下图:
然后又发现,5和12节点颜色一样了(可怕...........)
接下来我们想进行上一步的做法,却发现,当前节点(也就是12)的叔叔(也就是30)是黑色,(尴尬......) (根据3.2规则)
继续先判断,12节点的父节点作为爷爷节点的左子树(根据3.2.A规则),很明显5节点作为19的左子树
接下来可能要进行左旋或者是右旋了,
如果当前节点作为父节点的右子树,则进行左旋
如果当前节点作为父节点的左子树,则进行右旋
很明显,12这个节点为5节点的右子树,需要进行左旋.左旋之前,当前指针移动到当前节点的父节点(也就是5节点变为当前节点)
左旋后的图:
接下来又发现,5和12节点颜色一样了,然后5节点的叔叔是黑色,
继续先判断,5节点的父节点作为爷爷节点的左子树(根据3.2.A规则),很明显12节点作为19的左子树
要左旋或者右旋,但是5节点作为12的左子树,需要右旋
右旋需要注意:
1.先把5的父亲12节点变为黑色,再把5的爷爷变为红色
2.指针移到爷爷,也就是当前节点变为19节点了
3.以当前节点19进行右旋
右旋后的图:
红黑树插入完成
大家可以去下面的网址去练一下,红黑树的生成过程
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
创建红黑树代码