前言
红黑树的基本思想是用标准的二叉查找树和一些额外的信息(替换3-结点)来表示2-3树。树中的链接分为两种类型:
红链接:将两个2-结点连接起来构成一个3-结点。
黑链接:则是2-3树中的普通链接。
红黑树的定义
红黑树是含有红黑链接并满足下列条件的二叉查找树:
1、红链接均为左链接
2、没有任何一个结点同时和两条红链接相连
3、该树是完美黑色平衡的,即任意空链接到根结点的路径上的黑链接数量相同。
平衡化
左旋
当某个结点的左子结点为黑色,右子结点为红色,此时需要左旋。
前提:当前结点为h,它的右子结点为x;
左旋过程:
1、让x的左子结点变为h的右子结点:h.right = x.left;
2、让h成为x的左子结点:x.left = h;
3、让h的color属性变为x的color属性:x.color=h.color;
4、让h的color属性变为red: h.color = true;
右旋
当某个结点的左子结点是红色,且左子结点的左子结点也是红色,需要右旋
前提:当前结点为h,它的左子结点为x;
右旋过程:
1、让x的右子结点称为h的左子结点 : h.left = x.right
2、让h称为x的右子结点:x.right = h
3、让x的color变为h的color属性值: x.color = h.color
4、让h的color为red
颜色反转
当一个结点的左子结点和右子结点的color都为red的时候,也就是出现了临时4-结点,此时只需要把左右子结点变为black,同时让当前结点颜色变为red即可。
代码实现
public class RedBlackTree<k extends Comparable,v> {
private Node<k,v> root;
private int size;
private static final boolean RED = true;
private static final boolean BLACK = false;
//判断当前结点的父指向链接是否为红色
private boolean isRed(Node x){
if (x==null){
return RED;
}
return x.color==RED;
}
//左旋调整
private Node rotateLeft(Node h){
Node x = h.left;
// 1、让x的左子结点变为h的右子结点
h.right = x.left;
// 2、让h成为x的左子结点;
x.left = h;
// 3、让h的color属性变为x的color属性:x.color=h.color;
x.color = h.color;
// 4、让h的color属性变为red
h.color=RED;
return x;
}
//右旋调整
private Node rotateRight(Node h){
Node x = h.left;
// 1、让x的右子结点称为h的左子结点
h.left = x.right;
// 2、让h称为x的右子结点
x.right = h;
// 3、让x的color变为h的color属性值:
x.color = h.color;
// 4、让h的color为red
h.color=RED;
return x;
}
//颜色调整
private void flipColors(Node h){
if (h==null){
return;
}
if (h.left!=null){
h.left.color = BLACK;
}
if (h.right!=null){
h.right.color = BLACK;
}
h.color = RED;
}
//在整个树上完成插入操作
public void put(k key,v value){
root = put(root,key,value);
//确保根结点是黑色
root.color=BLACK;
}
//在指定树x上完成插入操作
private Node put(Node<k,v> h,k key,v value){
if (h==null){
size++;
return new Node(key,value,null,null,RED);
}
int com = key.compareTo(h.key);
if (com<0){
h.left = put(h.left,key,value);
}else if (com>0){
h.right = put(h.right,key,value);
}else {
h.value = value;
}
if (!isRed(h.left)&&isRed(h.right)){
h = rotateLeft(h);
}
if (h.left!=null&&isRed(h.left)&&isRed(h.left.left)){
h = rotateRight(h);
}
flipColors(h);
return h;
}
//根据key,从树中找出对应的值
public v get(k key){
return get(root,key);
}
//根据key,从指定树x中找出对应的值
private v get(Node<k,v> h,k key){
if (h==null){
return null;
}
int com = key.compareTo(h.key);
if (com>0){
return get(h.right,key);
}else if (com<0){
return get(h.left,key);
}else {
return h.value;
}
}
public int size(){
return size;
}
private class Node<k,v>{
k key;
v value;
Node<k,v> left;
Node<k,v> right;
boolean color;//由其父结点指向它的链接的颜色
public Node(k key, v value, Node<k, v> left, Node<k, v> right, boolean color) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
this.color = color;
}
}
}
测试
public static void main(String[] args) {
RedBlackTree<Integer, String> tr = new RedBlackTree<>();
tr.put(1,"hhh");
tr.put(2,"ccc");
tr.put(3,"bbb");
System.out.println(tr.get(1));
System.out.println(tr.get(2));
System.out.println(tr.get(3));
}