从2-3查找树开始
在二叉查找树中,每个结点都有1个键和2条指向子节点的链接,我们在此称其为2-结点。为了保证查找树的平衡性,我们引入一种新的结点,该结点具有2个键以及3条指向子节点的链接,称为3-结点。将含有2-结点和3-结点的树称为一颗2-3查找树。一颗2-3查找树的如下图所示。
对2-3树的查找同一般的二叉查找树类似,查找过程如下图所示,无需赘述。
下面重点讲一下2-3树中的插入操作。
向2-结点中插入新键
此类情况最为简单,直接将新键与2-结点中原来的键保存在一起形成一个新的3-结点就可以了。这样一来不会改变树的高度,也不会破坏2-3树的平衡性。下图给出了向一个2-结点中插入新键的过程。
向3-结点中插入新键
同3-结点的定义一样,4-结点具有3个键以及4条指向子结点的链接。向3-结点中插入新键时,首先会创建一个临时的4-结点,然后将4-结点进行分解完成插入。
1、该3-结点为树的根结点
下图显示了向一棵只含有一个3-结点的2-3树中插入一个新键的过程。首先创建一个临时的4-结点,然后将其分解为3个2-结点完成插入。插入之后树的高度增加了1。(这也是2-3树增加高度的唯一途径,即根节点的分裂)
2、该3-结点的父结点为2-结点
与情况1类似,首先创建一个临时的4-结点,然后将其进行分裂。只是,此处将分裂之后得到的3个2-结点中的中键与分裂前临时4-结点的父结点(是一个2-结点)相合并,形成一个3-结点,完成插入操作。此情况下的插入操作不会改变树的高度,因此就不会破坏树的平衡性。
3、该3-结点的父结点为3-结点
与情况2类似,首先创建一个临时的4-结点,然后分裂。此时原来的父结点(插入之前为一个3-结点)也变为了一个临时的4-结点。
递归向上进行此过程,直到遇见一个2-结点完成插入操作(此时树的高度不变);
或者到达根节点还没有遇到2-结点,那么该根节点就会形成一个临时的4-结点,然后进行根节点的分裂,树的高度增加1,完成插入操作。
通过上面的描述,可以知道2-3树的生长是从下向上的,与之前二叉查找树从上向下生长正好相反。即2-3树的高度增加只可能是根节点进行了分裂这一种情况所导致的。
可以证明,一棵大小为N的2-3树,其深度不会超过logN。
红黑树
与2-3树一一对应
前面已经叙述了2-3树的基本原理,通过引入3-结点,可以保持树的平衡性。但是2-3树的实现较为复杂,需要维持多种类型的结点。
红黑树的原理就是通过在二叉查找树中的2-结点引入一个额外的表示链接的颜色的信息,来实现2-3树。
红黑树中的每个结点都是传统的2-结点,同时每个结点中都存储了一个颜色的变量,表示该结点的父结点指向该结点的链接的颜色。这样整个树中的链接就分为了2种,红链接和黑链接。
对应的,红链接连接的两个2-结点整体与2-3树中的3-结点相对应,黑链接表示2-3树中的普通链接。也就是说,2-3树中的普通链接在红黑树中仍然用普通链接表示,而2-3树中的3-结点用一条红链接链接的2个2-结点表示(规定红链接是左链接)。3-结点与红链接的对应如下图所示。
红黑树的等价定义:
红黑树是含有红链接红黑链接的并满足以下条件的二叉查找树:
- 所有的红链接均为左链接
- 任何一个结点都不可能同时和2条红链接相连
- 改树是完美黑色平衡的,即任意空链接到根结点路径上的黑色链接数量相同。
根据上面的定义,可以将红黑树和2-3树进行一一对应。下面是一棵红黑树与一棵2-3树相对应的示意图。
红黑树的结点定义
与二叉查找树相比,红黑树的结点中新增加了表示其父结点指向其本身结点的链接颜色的变量,其定义如下。
private class Node {
private Key key; // key
private Value val; // associated data
private Node left, right; // links to left and right subtrees
private boolean color; // color of parent link, true is red and false is black
private int size; // subtree count
public Node(Key key, Value val, boolean color, int size) {
this.key = key;
this.val = val;
this.color = color;
this.size = size;
}
}
红黑树的插入操作
由于红黑树中所有结点都是2-结点,因此其查找操作与普通的二叉查找树相同,这里不再赘述。
下面主要分析一下红黑树中的插入操作。
左右旋转
在向红黑树中插入新键时,有可能会破坏树的平衡性,为了使树重新恢复到平衡状态,需要进行一系列的平衡操作。
其中,一个基本操作就是对结点的链接进行旋转。此处的旋转与AVL树中的单旋转相同,只是需要额外处理结点链接的颜色变化。旋转分为向左单旋转和向右单旋转。其示意图如下图所示。
颜色转换
向红黑树插入新键的过程中,有可能出现一个结点的两个子结点都是通过红链接与其相连接,相当于2-3树中形成了一个临时的4-结点。此类情况下,由于红黑树中任意一个结点不可能有两条红链接与其相连接(对应的,2-3树中不可能稳定存在4-结点,只可能是在对树的操作过程中临时存在),需要进行颜色转换。即是将两条红色的子链接转换为黑链接,而将该父结点本身链接的颜色转换为红链接,此情况类似于2-3树中4-结点向上分裂的过程。颜色转换过程的示意图如下图所示。
通过前面的描述