介绍
等价定义
含有红黑链接并满足下列条件的二叉查找树:
- 红链接均为左链接;
- 没有任何一个节点同时和两条红链接相连;
- 该树是完美黑色平衡,即任意空链接到根节点的路径上的黑链接数量相同;
以上定义和相应2-3树一一对应。
红黑树的插入算法结合了以下两种优势:
- 二叉查找树中简洁高效的查找方法;
- 2-3树中高效的平衡插入算法;
颜色表示
- 链接的颜色保存在节点的Nod数据类型的布尔变量color中;
- 红色链接为true,黑色链接为false;
- 节点的颜色为指向该节点的链接的颜色;
private static final boolean RED = true;
private static final boolean BLACK = false;
private class Node{
Key key; //键
Value val; //相关联的值
Node left, right; //左右子树
int N; //这颗子树中的节点总数
boolean color; //器父节点指向它的链接的颜色
Node(Key key, Value val, int N, boolean color){
this.key = key;
this.val = val;
this.N = N;
this.color = color;
}
}
private boolean isRed(Node x){
if(x == null) return false;
return x.color == RED;
}
旋转
左旋和右旋
左旋和右旋类似,交换一下left和right即可。
插入新键情况
1、向2-节点插入新键
向左插入:父节点成为一个3-节点
向右插入:错误的3-节点,向左旋转修正
2、向树底部的2-节点插入新键
第一种情况处理方法仍然适用
3、向一颗双键树(3-节点)中插入新键(三种情况)
- 新键大于原树中的两个键:由于有序性,连接到3-节点的右连接,此时出现两条红链接,将两链接由红变黑,得到一个三节点组成、高为2的平衡树。
- 新键小于原树中的两个键:连接到左边的空链接,出现两条连续的红链接,将上层红链接右旋,然后将两条红链接变为黑。
- 新键介于原树中的两个键之间:出现一条红左链接和一条红色右链接,将下层红链接左旋,然后将上层红链接右旋,然后将两条红链接变为黑。
每种情况都会产生一个同时连接到两条红链接的节点,需要去修正。
颜色转换
将子节点的颜色由红变黑,同时将父节点的颜色由黑变红。局部变换,不影响整棵树的黑色平衡性。
要点
- 根节点总是黑色的,红色的根节点说明根节点是3-节点的一部分;
- 每次插入之后后会将根节点设为黑色;
- 每当根节点由红变黑书店黑链接高度加1;
沿着插入点到根节点的路径向上移动时在所经过的每个节点中顺序完成以下操作,便可完成插入操作:
- 如果右子节点是红色的而左子节点是黑色的,进行左旋转;
- 如果左子节点是红色的且它的左子节点也是红色的,进行右旋转;
- 如果左右子节点均为红色,进行颜色转换;
红黑树的插入算法
public class RedBlackBST<Key extends Comparable<Key>, Value>{
private Node root;
private class Node{}
private boolean isRed(Node h){}
private rotateLeft(Node h){}
private rotateRight(Node h){}
private void flipColors(Node h){}
private int size(Node x){
if(x == null) return 0;
else return x.N;
}
public void put(Key key, Value val){
root = put(root, key, val);
root.color = BLACK;
}
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.val = val;
//三种变换情况
if(!isRed(h.left) && isRed(h.right)) h = rotateLeft(h);
if(isRed(h.left) && isRed(h.left.left)) h = rotateRight(h);
if(isRed(h.left) && !isRed(h.right)) h = rotateLeft(h);
h.N = size(h.left) + size(h.right) + 1;
return h;
}
}
参考