2-3查找树
定义:一颗2-3查找树或一颗空树,或由一下节点组成:
- 2-结点,含有一个键(及其对应的值)和两个链接,左链接指向的2-3树中的键都小于该结点,右链接指向的2-3树中的键都大于该结点
- 3-结点,含有两个键(及其对应的值)和三条链接,左链接指向的2-3树中的键都小于该结点,中链接指向的2-3树中的键都位于该结点的两个键之间,右链接指向2-3树中的键都大于该结点
红黑二叉查找树
定义:我们将树中的链接分为两种类型:
红链接将两个2-结点连接起来,构成一个3-结点
黑链接则是2-3树中的普通链接。
2-3查找树和红黑二叉查找树的关系
是一一对应的关系:
如果我们将红黑二叉树中的红链接所连接的两个结点合并,那么我们就会得到一颗2-3树。
相反,我们将一个2-3树中的3-结点画作由红色链接相连的两个2-结点,那么会得到一颗红黑树
用java表示红黑二叉查找树中的一个结点
private class Node{
Key key;
Value value;
Node left, right;
int N;
boolean color;
Node(Key key, Value value, int N, boolean color){
this.key = key;
this.value = value;
this.color = color;
}
}
在插入一个新的键时,我们主要通过旋转的操作帮助我们保证红黑树与2-3树之间的对应关系,以及保持平衡
private static final boolean RED = true;
private static final boolean BLACK = false;
//结点的计数器
private int size(Node x) {
if(x == null) {
return 0;
}else {
return x.N;
}
}
//左旋转一个h结点的右链接
Node rotateLeft(Node h) {
Node x = h.left;
h.right = x.left;
x.color = h.color;
h.color = RED;
x.N = h.N;
h.N = 1 + size(h.left) + size(h.right);
return x;
}
//右旋转h的左链接
Node rotateRight(Node h) {
Node x = h.left;
h.left = x.right;
x.right = h;
x.color = RED;
x.N = h.N;
h.N = 1 + size(h.left) + size(h.right);
return x;
}
红黑树的插入操作:
//分解结点时转换链接颜色
void flipColors(Node h) {
h.color = RED;
h.left.color = BLACK;
h.right.color = BLACK;
}
//结点的计数器
private int size(Node x) {
if(x == null) {
return 0;
}else {
return x.N;
}
}
//插入操作:
private Node put(Node h, Key key, Value val) {
if(h == null) {
return new Node(key, val, 1, RED);
}
int cmp = key.compareTo(h.key);
if(cmp < 0) {
h.left = put(h.left,key,val);
}else if(cmp > 0){
h.right = put(h.right, key, val);
}else {
h.value = val;
}
if(isRed(h.right) && !isRed(h.left)) {
h = rotateLeft(h);
}
if(isRed(h.left) && isRed(h.left.left)){
h = rotateRight(h);
}
if(isRed(h.left) && isRed(h.right)) {
flipColors(h);
}
h.N = size(h.left) + size(h.right) + 1;
return h;
}
private Node root;
public void put(Key key, Value val) {
root = put(root, key, val);
root.color = BLACK;
}
本文参考自《算法(第四版)》韦恩著
github链接