红黑树直接看有点懵,涂上颜色,颜色转换,状态调整,说实话,一上来这么弄,我都不想看,有些东西你会知道是这么回事,但是你不清楚为什么这么做?为什么要涂上颜色?我自己也不太喜欢死记硬背,感觉很伤脑子,而且过一段时间就忘记了,这不是我的风格。
2-3 树 同2-3-4树 是差不多的概念,这也是一种平衡树,但有不一样的地方:
同样 2-3树的插入、删除也会更复杂,大致的思路是:
删除的话就复杂很多,当然被篇文章就不仔细讨论这些了,他的优点包括平衡二叉树的所有优点:
当然缺点也非常致命:
所以2-3树在实际中很少使用。由于其需要大量的节点变换(从2-节点到3-节点到4-节点甚至到5-节点…),这些变换在实际代码中是很复杂的。所以现在几乎没有2-3树的具体实现。
但是由于2-3树的变化十分直观,因此前人在2-3树的理论基础上发明了红黑树。
2-3-4树 与 2-3树唯一的差别就在于多了一个4结点,容纳3个key,其他差别不太大,红黑树其实更类似2-3-4树:
有一些博客里讲解了红黑树的几个特征性质,当然我们也提一下,虽然这些特征比较麻烦:
这是约束一颗红黑树的条件,也就是符合这些条件就是红黑树,其实还有一点:新插入的结点都是红色节点。红色节点插入树中之后,根据约束条件来更改颜色、调整树结构。
插入相对还是比较简单的。同样结点数目构成的红黑树有很多种,这些不同的情况都可以通过染色、平衡来实现,那么问题来了?你依据什么样的准则来染色、调整?因为很多种染色、平衡操作都可以使得不平衡的红黑树变得平衡,那么你设计的调整准则是什么?
看到一篇文章讲解插入操作,讲解的还是比较好的,插入主要关注三种情况,这三种情况会因为一开始插入,或者是因为调整之后出现的情况,并且并不是调整一次就结束,会反复调整,我们先看下伪代码:
RB-INSERT-FIXUP(T,z)
1 while color[p[z]] = RED
2 if p[z] = left[p[p[z]]]
3 y ← right[p[p[z]]]
4 if color[y] = RED
5 color[p[z]] ← BLACK ▹ Case 1
6 color[y] ← BLACK ▹ Case 1
7 color[p[p[z]]] ← RED ▹ Case 1
8 z ← p[p[z]] ▹ Case 1
9 else if z = right[p[z]]
10 z ← p[z] ▹ Case 2
11 LEFT-ROTATE(T, z) ▹ Case 2
12 else
13 color[p[z]] ← BLACK ▹ Case 3
14 color[p[p[z]]] ← RED ▹ Case 3
15 RIGHT-ROTATE(T, p[p[z]]) ▹ Case 3
16 else (same as then clause with "right" and "left" exchanged)
17 color[root[T]] ← BLACK
代码可能有点难懂,参数说明:z是插入节点的指针,T是树。总结一下代码流程:
while ( z节点父节点 是红色 ):
if z节点的父节点 == z节点 祖父节点的左节点:
y = z节点 祖父节点右节点
if y 颜色 == red
第一种情况调整 ▹ 注意
z = z节点的祖父节点
else if z是右孩子 # 这也说明 y 颜色是黑色
z = z节点的父节点
第二种情况调整 ▹ 注意
else # z是左孩子 ,y 颜色是黑色
第三种情况调整 ▹ 注意
else # 隐藏含义: z节点的父节点 == z节点 祖父节点的右节点
# 剩下的操作跟上面一样,只不过 左右互换一下
最后将 根节点 颜色 改为 黑色
注意几点:
看的时候注意几个问题:
第一种情况下:为什么根节点是红色?这不就不符合红黑树定义了嘛?
因为有最后的一个步骤将根节点置位黑色,所以其实也不算是一种失误
第二种情况、第三种情况 下 原有结构也是有问题的?
因为我们看到了的只是一部分结构,单纯的这种树结构是不会出现的,因为根本不符合红黑树的定义,建议看下教你透彻了解红黑树。里面有完整的树结构,第二种、第三种其中一部分结构,并且也有可能是调整之后出现的情况
第二种情况、第三种情况的联系
如果你仔细看,你会发现第二种情况跟第三种情况是连续的,第二种情况之后就开始执行第三种情况,
第三种情况之后好像出现了不平衡的情况
第三种情况是先变色,再旋转,但其实第三种情况的初始状态就不会存在,也就是不存在单纯的第三种情况的初始状态,它只是红黑树的一部分。完整的树下它是平衡的。
出现连续的两个红色节点的情况,比如第三种情况,有点像2-3-4树
红-红-黑 就像 一个 4结点,只不过在2-3-4树中是一个结点,在红黑树中要变色、调整,使得平衡。
第三种情况之后,似乎就结束调整了
没错,我们看图中第三种情况调整之后, z z z的节点位置,发现它不满足while循环的条件,也就会跳出循环,所以可以认为这是最后的一个步骤。
为什么是这三种情况?
很奇怪的一点就是为什么是这三种情况?这三种情况似乎是可以连续起来的,2、3、1这样的顺序,不过也只是猜测,各种情况分析之后其实也就只有这几种情况需要调整了,具体的还要继续研究一下。
插入的操作大致是这样,一些不需要调整的情况如下:
三种情况的另一种换言之,可以加强大家认识:
左右反过来的情况是一样的,处理过程也是类似的,这里不赘述。
TreeSet treeSet = new TreeSet();
treeSet.add(4);
treeSet.add(1);
treeSet.add(2);
treeSet.add(3);
treeSet.add(5);
treeSet.add(6);
treeSet.add(7);
以上代码是我用来测试的代码,通过debug来查看了每个节点的颜色,得到了最终树的形状:
我比较奇怪,为啥 这个不是其他结构,因为4也可以作为根节点,得到一个更加平衡的二叉树,于是我猜想是不是跟节点插入顺序有关,于是我重新弄了一个代码:
TreeSet treeSet = new TreeSet();
treeSet.add(4);
treeSet.add(1);
treeSet.add(5);
treeSet.add(2);
treeSet.add(6);
treeSet.add(3);
treeSet.add(7);
我debug看了一下,还是结构发生了变化,
插入的顺序跟最终的结果关系很大,有可能本来就很平衡,不需要调整。
删除结点 一共有6种情况,真是复杂,慢慢来分析,这里会先讲解删除树节点的大致操作,然后来了解一下二叉树删除节点之后的调整过程,定一个基调,用来分析红黑树的删除:
这两种情况比较好弄,但是不太好理解,第一种比较好理解,第二种不太好理解,因为极有可能会造成左子树黑色结点少了一个,这样,根节点到叶子节点的路径上黑色节点数目不太一致,这一点先保留意见,之后来测试一下场景。
还有另外四种情况,代码先上:
1 while x ≠ root[T] and color[x] = BLACK
2 do if x = left[p[x]]
3 then w ← right[p[x]]
4 if color[w] = RED
5 then color[w] ← BLACK ▹ Case 1
6 color[p[x]] ← RED ▹ Case 1
7 LEFT-ROTATE(T, p[x]) ▹ Case 1
8 w ← right[p[x]] ▹ Case 1
9 if color[left[w]] = BLACK and color[right[w]] = BLACK
10 then color[w] ← RED ▹ Case 2
11 x ← p[x] ▹ Case 2
12 else if color[right[w]] = BLACK
13 then color[left[w]] ← BLACK ▹ Case 3
14 color[w] ← RED ▹ Case 3
15 RIGHT-ROTATE(T, w) ▹ Case 3
16 w ← right[p[x]] ▹ Case 3
17 color[w] ← color[p[x]] ▹ Case 4
18 color[p[x]] ← BLACK ▹ Case 4
19 color[right[w]] ← BLACK ▹ Case 4
20 LEFT-ROTATE(T, p[x]) ▹ Case 4
21 x ← root[T] ▹ Case 4
22 else (same as then clause with "right" and "left" exchanged)
23 color[x] ← BLACK
4种情况主要有:
其实通过上述的情况来看,这里的删除调整不是一下子就结束了,也要进行插入调整,两个调整之后还要进行多次调整,最终可以得到一颗符合条件的平衡树。
来看一个代码实现:
TreeSet treeSet = new TreeSet();
treeSet.add(4);
treeSet.add(1);
treeSet.add(5);
treeSet.add(2);
treeSet.add(6);
treeSet.add(3);
treeSet.add(7);
treeSet.remove(2);
通过debug发现删除前后的差别是,删除前:
删除后:
目前树结构的有:
红黑树也是一种AVL树,红黑树是用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。
实际应用中,根据业务特点来选择:
漫画算法:什么是红黑树?(通俗易懂)
2-3树到红黑树
红黑树从头至尾插入和删除结点的全程演示图
RedBlack.pdf