红黑树的学习过程

这是一次向大佬学习红黑树的过程的记录。
原贴(2-3树):http://www.cnblogs.com/yangecnu/p/Introduce-2-3-Search-Tree.html
原贴(红黑树):http://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html

一、从2-3树谈起

        红黑树是在2-3树的基础上提出的,理解2-3树将会很方便我们理解红黑树。

        2-3树也是一种平衡查找树,它的核心思想是在原有的二叉查找树基础上,当为目标节点新增一个子节点可能引起树的失衡时(我的理解是插入节点导致左右子树深度差值大于1时),放弃原有插入操作,改为将我们要插入的数据放到目标节点内部,即让目标节点多存储一个数据以避免深度的增加。

一个便于理解的例子:
这里写图片描述
这里写图片描述

1.2-3树的一些概念

        2-3树中的“2”和“3”指代的是节点的子树数量。         显而易见,2-3树中的“2节点”与通常二叉查找树中的节点相同,而在上图中所创造的“3节点”则稍有不同,它储存了两个数据(设为A、B,且A<B),并且(最多)可以拥有3个子树,一般规定其左子树的所有节点都<A,中间子树的所有节点都在A、B之间,右子树的所有节点都>B。 2-3树的查找方法与一般二叉查找树的查找方法也几乎相同,不做赘述。

2.2-3树的插入、删除操作

        2-3树的插入操作可以分为两类:往一个“2节点”中插入一个新数据;或往一个“3节点”中插入一个新数据。

“2节点”即常规的二叉查找树节点,往“2节点”中插入数据非常简单,将新数据放到“2节点”中变成“3节点”即可;
往“3节点”中插入数据一般有如下步骤:
将新数据放到“3节点”中,创造一个临时的“4节点”,也就是说这个临时的“4节点”储存其原有的两个数据和我们新放入的数据;

依情况分析:

        如果该节点没有父母节点,将这个节点“分裂”为3个节点,然后提出中间数据成为父母节点,最小数据所在节点成为左子树,最大数据成为右子树;
        如果该节点有父母节点,并且父母节点是一个“2节点”,同样将这个节点分裂,不过这一次中间数据直接放到其父母节点中去,也就是将父母节点变为一个“3节点”,最小数据和最大数据则成为这个“3节点”的某两个子树;
        如果该节点有父母节点,并且父母节点是一个“3节点”,同样将中间数据提出来放到其父母节点中去,最小和最大数据成为父母节点的某两个子树,但注意这时候父母节点是一个临时的“4节点”,需要重复这个(提出中间数据放到父母节点的)过程。

2-3树的删除操作依然采用一般平衡二叉树删除操作的思想,即“补位”。

        首先找到待删除节点,如果该节点是叶子节点且是“2节点”,直接删掉;如果是叶子节点且是“3节点”,删掉要删的数据将它变成“2节点”即可;
        如果该节点不是叶子节点,每一次都寻找左子树中最大的数据(或者右子树中最小的元素)并补到待删数据的位置,这时候用来补位的数据那里又空出来了,如果它不是叶子,则重复这个“补位”的过程。

2-3树一个非常麻烦的地方就是上面提到的创造临时“4节点”,然后提出中间数据放到父母节点,最小最大数据分别做为父母节点的某子树的过程。一方面,你提上去的数据需要和父母节点中的数据进行比较、排序,另一方面,最小最大数据也需要和(排好序的)父母节点中的数据进行比较来决定自己的位置(是左、中、还是右子树)。此外,2-3树的杂乱结构个人认为也破坏了二叉树的某种美感(笑)。

为了解决这个问题,人们提出了红黑树。

二、红黑树
1.红黑树的一些概念

        为了避免创立繁琐的“3节点”,人们选择在一般的二叉查找树的基础上,对连接“2节点”的边上动手脚,并做出约束:如果两个节点之间的连接是红色的,那么这两个节点合在一起将表示一个“3节点”。换言之,当我们忽略红色连接时,两端的节点将被看成是一个节点,即2-3树中的“3节点”。

        同时人们约定一棵平衡二叉树的红色连接总是左倾的。(当然也可以约定成右倾的,但决不允许同时存在左倾与右倾的红色连接。设想一个节点与其左右子树都是红色连接,那么其同时与左右子树都可以构成一个“3节点”,实质上是建立了一个“4节点”,而已平衡的二叉查找树中是不应当存在“4节点”的。)
节点的颜色其实记载的是其与父母节点之间连接的颜色
        此外,由2-3树的插入操作可知2-3树中的根节点总是“2节点”,那么对应红黑树中的根节点总是黑色的

2.红黑树的插入与删除操作

        我们已知2-3树是一种平衡的二叉查找树,而2-3树的平衡方法是将引起深度差值大于2的数据放到“2节点”中去,对应到红黑树,其实就是“忽略”红色连接,将红色连接两头的节点看成是一个节点(3节点)。再换个角度,也即人们常说的:从根节点到所以叶子结点的路径上,黑色连接的个数都相同,红色节点不影响深度。

        实际插入过程中,我们总是将插入的节点设置为红色,这样可以避免改变从根节点到新增节点路径上黑色连接的数量。但这并不意味着插入操作后树就平衡了,由于我们约定红色连接总是左倾的,同时也不应该存在一个节点同时有两个红色连接的情况(再次重申,这种情况对应2-3树中的“4节点”),还要进行一定的平衡操作。

        不妨思考新增一个节点之后可能出现的违法情况有哪些:
1.这里写图片描述
        这种情况新增节点后红色连接右倾,很容易想到的解决方案是将新增节点变为左子节点,考虑到数据的大小关系,最终对父母节点采用左旋操作。
这里写图片描述
        注意这里用“新增节点”的说法并不准确,实际的平衡操作往往是一个不断递归的过程(即我们不一定总是对新增节点的父母节点进行左旋,可能也会对某个已存在节点的父母节点进行左旋)。如果那个节点有左子树的话,左旋过程中应当设置为原父母节点的右子树。(图中未画出)
2.这里写图片描述
        这种情况我们已经多次提到,它对应2-3树中的“4节点”,由于红色连接可忽略,父母节点的数据其实就相当于“4节点”之中的中间数据,左子树数据对应最小数据,右子树数据对应最大数据。
        在2-3树中的解决方法是将中间数据提出来,提到上层去。对应到红黑树,就是将左右子节点设置为黑色,父母节点则设置为红色(如果父母节点是根节点则不必设置为红色)。
这里写图片描述
        同样的,平衡过程往往是一个递归的过程,我们解决了这一层的冲突,由于将父母节点设置为了红色,可能造成新的冲突。
3.这里写图片描述
        这种情况目标节点拥有两个红色连接,其实是另一种形式的“4节点”。解决方法是对目标节点的父母节点进行右旋操作。
这里写图片描述
        显然这一次右旋之后,我们还要调用一次冲突2之中对目标节点重新找色的方法。

整个树的平衡过程其实就是这三种方法(左旋、重新着色、右旋)不断调用的过程。不妨思考一下为什么有些“冲突情况”其实根本不会出现。

3.红黑树的删除操作
红黑树的删除操作依然采用的“补位”方法。换言之我们最终删除的总是一个叶子节点,考虑一下一棵已平衡的红黑树叶子节点的可能情况:
最终被删除的节点也可能是左子节点
这里写图片描述
最终被删除的节点也可能是左子节点
(个人能力有限,可能会有疏漏)
仔细观察可以发现,无论是上述哪一种情况,删除之后都不会改变红黑树的三大性质:
1)根节点黑色;
2)红色连接左倾;
3)一个节点最多只能有一个红色连接,且根节点到任意叶子节点的黑色连接数相等。
因此,红黑树的删除操作就是一般二叉查找树的删除操作。

猜你喜欢

转载自blog.csdn.net/saasanken/article/details/76998264