# 学习红黑树的思考

###### 红黑树的特性
``````①红节点均为左节点
②不存在拥有两个红子节点的节点
③红黑树是平衡二叉树，任意叶子结点到根节点的路径上黑色节点的个数相同
④根节点必为黑色
⑤如果节点是红色，则其子节点必为黑色
``````

##### 实现
###### 颜色表示

``````public static final RED = true;
public static final BLACK = false;
``````
##### 节点数据结构
``````class Node {

private Key key;
private Value value;
private boolean color;  //节点颜色
private int size;  //以节点为根的树的节点个数
private Node right, left;

public Node(Key key, Value value, boolean color, int size){
this.key = key;
this.value = value;
this.color = color;
this.size = size;
}

}
``````
##### 红黑树的平衡实现

``````public boolean isRed(Node node){
if(node == null){
return false;
}
return node.color;
}
``````
###### 1.变色

``````public void flipColors(Node node){
node.color = !node.color;
node.left.color = !node.left.color;
node.right.color = !node.right.color;
}
``````

###### 2.左旋转

``````public Node rorateLeft(Node node){
Node temp = node.right;  //当前节点的右节点
node.right = temp.left;  //当前节点的右节点变为其右节点的左节点
temp.left = node;  //当前节点变为其右节点的左节点
//改变颜色
temp.color = temp.left.color;
temp.left.color = RED;
temp.size = temp.left.size;
//调整大小
temp.left.size = size(temp.left.left) + size(temp.left.right) + 1;
return temp;
}
``````

###### 3.右旋转

``````public Node rorateRight(Node node){
Node temp = node.left;  //记录当前节点的左节点
node.left = temp.right;  //当前节点的左节点变为其左节点的右节点
temp.right = node;  //当前节点变为其左节点的右节点
//调整颜色
temp.color = temp.right.color;
temp.right.color = RED;
//调整大小
temp.size = temp.right.size;
temp.right.size = size(temp.right.left) + size(temp.right.right) + 1;
return temp;
}
``````

###### 补充

``````public int size(Node node){
if(null == node){
return 0;
}
return 1 + size(node.left) + size(node.right);
}
``````

##### 红黑树插入操作

``````public void insert(Key key, Value value){
//key不可以为null
if(null == key){
throw new IllegalArgumentException("argument key of insert() can't be null");
}
//插入操作可能造成根节点变化
root = insert(root, key, value);
//保证根节点为BLACK
root.color = BLACK;
}

private Node insert(Node node, Key key, Value value){
//遇到null节点创建新节点
if(null == node){
node = new Node(key, value, RED, 1);
return node;
}
//否则进行比较
int cmp = key.compareTo(node.key);
if(cmp == 0){  //相等更新value即可
node.value = value;
}else if(cmp > 0){  //key大于node.key，右子树继续插入操作
node = insert(node.right, key, value);
}else{  //key小于node.key，左子树继续插入操作
node = insert(node.left, key, value);
}
//完成插入后，红黑树平衡可能被破坏，需要重新调整平衡
insertBalance(node);
}

public void insertBalance(Node node){
//当前节点左节点为黑节点，右节点为红节点——左旋转
if(!isRed(node.left) && isRed(node.right)){
node = rorateLeft(node);
}
//当前节点的左节点及其左节点的左节点为红色节点——右旋转
if(isRed(node.left) && isRed(node.right)){
node = rorateRight(node);
}
//当前节点左右节点都是红色节点——变色
if(isRed(node.left) && isRed(node.right)){
flipColors(node);
}
return node;
}
``````

##### 删除操作

###### 1.删除最小键值

``````①如果当前节点是红色且是最小键，直接删除即可
②当前节点是3节点中的黑色节点，继续递归，下一个节点定是红色节点，只需要判断红色节点是否是最小键即可
``````

①借一个节点使得当前节点为红节点，对应2-3树中的4节点

###### ！！！注意这里的h节点指的是当前节点的父节点

②借一个节点使得当前节点的左节点为红色节点，对应2-3树中的3节点

###### ！！！注意这里的h节点指的是当前节点的父节点
``````public void deleteMin(){
//空树无法删除
if(null == root){
throw new NoSuchElementException("tree is empty!");
}
//根节点左右节点都为黑色节点，置根节点为红色
if(!isRed(root.left) && !isRed(root.right)){
root.color = RED;
}
root = deleteMin(root);
//树非空，根节点颜色置黑
if(!isEmpty()){
root.color = BLACK;
}
}

private Node deleteMin(Node node){
//当前节点的左节点为null，即为最小节点
if(null == node.left){
return null;
}
//保证当前节点或其左节点为红色，注意是从父节点入手
if(!isRed(node.left) && !isRed(node.left.left)){
//制造红色节点
node = moveRedLeft(node);
}
//递归删除最小键节点
node = deleteMin(node.left);
//调整平衡
return deleteBalance(node);
}

private Node moveRedLeft(Node node){
//先变色
flipColors(node);
//判断节点右节点的左节点是否红色，若是，按第二种方式操作
if(isRed(node.right.left)){
node.right = rorateRight(node.right);
node = rorateLeft(node);
flipColors(node);
}
return node;
}

private Node deleteBalance(Node node){
if(isRed(node.right)){
node = rorateLeft(node);
}
if(isRed(node.left) && isRed(node.right)){
node = rorateRight(node);
}
if(isRed(node.left) && isRed(node.right)){
flipColors(node);
}
return node;
}
``````

moveRedLeft()函数即上面两张图片对应的转换操作，当当前节点的右节点的左节点颜色为红色时按照第二种方式进行转换，将当前节点的左节点的左节点变成红色。否则当前节点左节点为红色，左节点的左节点为黑色。（看代码更好理解）

###### 2.删除最大键值节点

①生成一个4节点

！！！注意这里的h节点指的是当前节点的父节点
②借一个节点使得当前节点的右节点为红色节点，对应2-3树中的3节点

！！！注意这里的h节点指的是当前节点的父节点
``````public void deleteMax(){
//检查二叉树非空
if(isEmpty()){
throw new NoSuchElementException("tree is empty!");
}
//当根节点左右节点都为黑色节点，将根节点变红
if(!isRed(root.left) && !isRed(root.right)){
root.color = RED;
}
//删除最大键，删除过程根节点可能变化
root = deleteMax(root);
//树非空，保证根节点为黑色
if(!isEmpty()){
root.color = BLACK;
}
}

private Node deleteMax(Node node){
//当前节点存在红色左节点，进行右旋转创造红色的右节点
if(isRed(node.left)){
node = rorateRight(node);
}
//节点无右节点，即为最大键，删除
if(null == node.right){
return null;
}
//保证node或node.right为红节点，注意也是从父节点入手
//因为3节点是用红节点来模拟的，红节点不可能是右孩子，所以不可能是h.right.right
if(!isRed(node.right) && !isRed(node.right.left)){
node = moveRedRight(node);
}
node.right = deleteMax(node.right);
//注意删除后需要重新平衡红黑树
return deleteBalance(node);
}

private Node moveRedRight(Node node){
//变色
flipColors(node);
//相当于完成图2，将右节点的右节点变红，创造3节点操作
if(isRed(node.left.left)){
node = rorateRight(node);
flipColors(node);
}
return node;
}
``````
###### 3.删除操作

``````public void delete(Key key){
//判断树非空
if(isEmpty()){
throw new NoSuchElementException("tree is empty!");
}
//key不得为null
if(null == key){
throw new IllegalArgumentException("argument of delete can't be null");
}
//检查键是否存在
if(!contains(key)){
return ;
}
//根节点左右节点都是黑色，根节点变红
if(!isRed(root.left) && !isRed(root.right)){
root.color = RED;
}
root = delete(root, key);
//树非空，根节点为黑色
if(!isEmpty()){
root.color = BLACK;
}
}

private Node delete(Node node, Key key){
//当前节点的键大于待删除的键，需要在当前节点左子树中递归删除
//当前节点的左右节点都是黑色节点，通过moveRedLeft创造红色左节点
if(key.compareTo(node.key) < 0){
if(!isRed(node.left) && !isRed(node.left.left)){
node = moveRedLeft(node);
}
node.left = delete(node.left, key);
}else{  //待删除的键大于等于当前节点的键
//如果当前节点的左节点为红色——右旋转
//该步操作创造红色右节点
if(isRed(node.left)){
node = rorateRight(node);
}
//如果待删除key与当前节点key相等，切当前节点右节点为空——可以直接删除
if(key.compareTo(node.key) == 0 && node.right == null){
return null;
}
//当前节点key小于待删除的key，需要在其右子树中进行删除
//当前节点的左右节点都是黑色节点，通过moveRedRight创造红色右节点
if(!isRed(node.right) && !isRed(node.right.left)){
node = moveRedRight(node);
}
//旋转后的当前节点key若等于待删除key
//替换当前节点为其右子树的最小节点，之后删除其右子树的最小节点即可
if(key.compareTo(node.key) == 0){
Node temp = min(node.right);
node.key = temp.key;
node.value = temp.value;
node.right = deleteMin(node.right);
}else{  //若不相等，继续在右子树中执行删除操作
node.right = delete(node.right, key);
}
return deleteBalance(node);
}
``````
##### 给出完整的红黑树操作
``````public class RedBlackTree <Key extends Comparable, Value>{

private Node root;
private static final boolean RED = true;
private static final boolean BLACK = false;

private class Node{

private Key key;
private Value value;
private boolean color;
private int size;

public Node(Key key, Value value, boolean color, int size){
this.key = key;
this.value = value;
this.color = color;
this.size = size;
}

}

private boolean isRed(Node node){
if(null == node){
return false;
}
return node.color;
}

private int size(Node node){
if(null == node){
return 0;
}
return 1 + size(node.left) + size(node.right);
}

public boolean isEmpty(){
return null == root;
}

public Node min(){
if(isEmpty()){
return null;
}
return min(root);
}

private Node min(Node node){
if(null == node.left){
return node;
}
return min(node.left);
}

public Node max(){
if(isEmpty()){
return null;
}
return max(root);
}

private Node max(Node node){
if(null == node.right){
return node;
}
return node.right;
}

public Value get(Key key){
if(null == key){
throw new IllegalArgumentException("argument of get() can't be null!");
}
return get(root, key);
}

private Value get(Node node, Key key){
if(null == node){
return null;
}
int cmp = key.compareTo(node.key);
if(cmp == 0){
return node.value;
}else if(cmp > 0){
return get(node.right, key);
}else{
return get(node.left, key);
}
}

public boolean contains(Key key){
if(null == get(key)){
return false;
}
return true;
}

public void insert(Key key, Value value){
if(null == key){
throw new IllegalArgumentException("argument of get() can't be null!");
}
root = insert(root, key, value);
root.color = BLACK;
}

private Node insert(Node node, Key key, Value value){
if(null == node){
node = new Node(key, value, RED, 1);
return node;
}
int cmp = key.compareTo(node.key);
if(cmp == 0){
node.value = value;
}else if(cmp > 0){
node.right = insert(node.right, key, value);
}else{
node.left = insert(node.left, key, value);
}
return insertBalance(node);
}

public void deleteMin(){
if(isEmpty()){
throw new NoSuchElementException("tree is empty!");
}
if(!isRed(root.left) && !isRed(root.right)){
root.color = RED;
}
root = deleteMin(root);
if(!isEmpty()){
root.color = BLACK;
}
}

private Node deleteMin(Node node){
if(null == node.left){
return null;
}
if(!isRed(node.left) && !isRed(node.left.left)){
node = moveRedLeft(node);
}
node.left = deleteMin(node.left);
return deleteBalance(node);
}

public void deleteMax(){
if(isEmpty()){
throw new NoSuchElementException("tree is empty!");
}
if(!isRed(root.left) && !isRed(root.right)){
root.color = RED;
}
root = deleteMax(root);
if(isEmpty()){
root.color = BLACK;
}
}

private Node deleteMax(Node node){
if(null == node.right){
return null;
}
if(!isRed(node.right) && !isRed(node.right.left)){
node = moveRedRight(node);
}
node.right = deleteMax(node.right);
return deleteBalance(node);
}

public void delete(Key key){
if(!contains(key)){
return ;
}
if(null == key){
throw new IllegalArgumentException("argument of get() can't be null!");
}
if(!isRed(root.left) && !isRed(root.right)){
root.color = RED;
}
root = delete(root, key);
if(!isEmpty()){
root.color = BLACK;
}
}

private Node delete(Node node, Key key){
if(key.compareTo(node.key) < 0){
if(!isRed(node.left) && !isRed(node.left.left)){
node = moveRedLeft(node);
}
node.left = delete(node.left, key);
}else{
if(isRed(node.left)){
node = rorateRight(node);
}
if(key.compareTo(node.key) == 0 && null == node.right){
return null;
}
if(!isRed(node.right) && !isRed(node.right.left)){
node = moveRedRight(node);
}
if(key.compareTo(node.key) == 0){
Node temp = min(node.right);
node.key = temp.key;
node.value = temp.value;
node.right = deleteMin(node.right);
}else{
node.right = delete(node.right, key);
}
}
return deleteBalance(node);
}

private Node insertBalance(Node node){
if(!isRed(node.left) && isRed(node.right)){
node = rorateLeft(node);
}
if(isRed(node.left) && isRed(node.left.left)){
node = rorateRight(node);
}
if(isRed(node.left) && isRed(node.right)){
flipColors(node);
}
return node;
}

private Node deleteBalance(Node node){
if(isRed(node.right)){
node = rorateLeft(node);
}
if(isRed(node.left) && isRed(node.left.left)){
node = rorateRight(node);
}
if(isRed(node.left) && isRed(node.right)){
flipColors(node);
}
return node;
}

private void flipColors(Node node){
node.color = !node.color;
node.left.color = !node.left.color;
node.right.color = !node.right.color;
}

private Node rorateLeft(Node node){
Node temp = node.right;
node.right = temp.left;
temp.left = node;
temp.color = node.color;
node.color = RED;
temp.size = node.size;
node.size = 1 + size(node.left) + size(node.right);
return temp;
}

private Node rorateRight(Node node){
Node temp = node.left;
node.left = temp.right;
temp.right = node;
temp.color = node.color;
node.color = RED;
temp.size = node.size;
node.size = 1 + size(node.left) + size(node.right);
return temp;
}

private Node moveRedLeft(Node node){
flipColors(node);
if(isRed(node.right.left)){
node.right = rorateRight(node.right);
node = rorateLeft(node);
flipColors(node);
}
return node;
}

}
``````