本来打算一下写完的,图太多了,自己都没耐心看完,就把插入和删除分开写了。
红黑树有5个性质
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
性质5.每个叶节点是黑色的。
性质5是一本书里额外添加的,本来只有前4个性质,性质5的作用是为了测试红黑树的性质4我简单借张图片表示,看到那些NIL了吗,他们就是性质5的叶节点,也是性质4的测试方法
这几个性质记好了,我们就直接开始建造树,然后便建造便分析各种情况。
先总结各种情况,一会你看完下面例子在扭头看总结也可以
父亲节点为黑直接加入即可
父亲叔叔节点为红,将爷爷变红,父亲叔叔变黑直接加入
父亲为红叔叔为黑,分2种情况
1,父亲为左子树自己也是左子树或者父亲为右子树自己也为右子树,父亲变黑爷爷变红,自己为左子树右旋转,自己为右子树左旋转
2父亲为左子树自己是右子树或者父亲为右子树自己也为左子树,先和父亲替换下位置然后以父亲为新加入的节点进行变化
我们先随便选择一组数字吧(前面数字我随便选的,后面为了满足各种插入时的情况就特意选择的)
77,66,88,21,3,5,99,1024,7,1,89,2
插入规则为二叉树的插入
二叉查找树的插入很简单,先把要插入的节点的key与根进行比较,小则和根的左孩子做比较,大则跟右孩子作比较,直到找到叶子节点。
第一步,我们把77作为根结点
根结点必须为黑色
第二步,66和88两个子节点的插入
这里引出一个规则,红黑树除了根结点的所有结点插入时颜色默认为红色,原因,性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点,插入一个黑色节点就会违反这个规则。
第3步,21的插入
这个插入引出了插入的一个性质,叔叔和父亲都是红色
在这里我们要是直接插入便会违法性质3红树的节点必须是黑色,要是把21直接插入便会违法性质4
这种情况,也就是父亲节点和叔叔节点都是红色的,我们这样解决,把父亲和叔叔便黑,爷爷变红(如果爷爷为根节点则不需要改变颜色)
因为爷爷为根结点,所以变黑
第4部插入3
这里有一个问题我们平时插入的时候是根据叔叔和父亲插入的,这里没有叔叔啊,其实是有的,你忘记性质5了,叔叔是黑色的(如下图)
这样叔叔是不是就很明显 了我们在回归怎么插入3这个问题
父亲为红色,叔叔为黑色这种情况我们要进行旋转,旋转前要换颜色也就是把父亲变为黑色爷爷变为红色
然后进行右旋转
旋转的过程中并不会引起红黑树的平衡,原因自己想去。
第五部插入5
父亲结点和叔叔结点都为红色,和前面方法一样父亲叔叔变黑,爷爷变红
红黑树平衡为影响(这一步可能会影响爷爷节点的平衡,所以在代码需要判断)
第6部99,父亲为黑,直接插入即可
第7部1024
父亲为红叔叔为黑,将父亲变黑爷爷变红,旋转
第8部7
父亲节点变黑,爷爷结点变红,旋转
到这里我们还有3种情况没有说,我们选择3个数说一下剩余的3种情况
我们先插入1
父亲节点和叔叔节点都是红色,父亲和叔叔变黑,爷爷变红
5和21都是红色不符合规则
5的父亲节点为红色,叔叔节点为黑色,将5的父亲变黑爷爷变红
从爷爷77进行旋转(旋转都是从爷爷转的)
插入1023
这步很有意思,靠仔细看了
父亲和叔叔为红,将爷爷变黑,父亲叔叔变黑
99的父亲和叔叔为红,同样道理,父亲叔叔变黑,爷爷变红
爷爷为根结点,所以爷爷变黑
2的插入
2的插入是最后一块了,这个一说关于红黑树的插入就结束了,剩下的就是比较简单的代码了,我明天有空就把代码打出来。
这种情况我们不能直接把1变黑,3变红,因为这种变法在多数情况下更容易起冲突,虽然这样做也并不违反红黑树的平衡
我们需要先左旋转,让1成为新插入的数
然后父亲变黑(也就是2),爷爷变红,也就是3,进行一次旋转即可
困了,代码和删除明天在写,挺简单的,我感觉应该通俗易懂吧,另外你们想要什么样的代码可以私聊java,C/C++,C#,python,Scala,lua,Kotlin,go这些都可以,其他的看我会不会了,但是我有没有时间写就不一定了