红黑树
红黑树的查找、插入和删除时间复杂度都为O(log2N)
/**
* 1. 定义颜色
* 2. 创建BRNode 结点
* 3. 辅助方法:parentOf(node)、isRed(node)、isBlack(node)、
* setRed(node)、setBlack(node)、isOrderPrint()
* 4. 左旋 leftRotate(node)、右旋 rightRotate(node)
* 5. 公开插入 insert(K key,V value)
* 6. 内部插入 insert(RBNode node)
* 7. 修正插入导致的失衡 insertFixUp(RBNode node)
* 8. 测试
*/
public class RBTree<K extends Comparable<K>, V> {
//1
private static final boolean RED = true;
private static final boolean BLACK = false;
//树根
private RBNode root;
public RBNode getRoot() {
return root;
}
public void setRoot(RBNode root) {
this.root = root;
}
//3.1 获取父结点 parentOf(node)
private RBNode parentOf(RBNode node){
if(node != null){
return node.parent;
}
return null;
}
//3.2 是否为红结点 isRed(node)
private boolean isRed(RBNode node){
if(node != null){
return node.color==RED;
}
return false;
}
//3.3 是否为黑结点 isBlack(node)
private boolean isBlack(RBNode node){
if(node != null){
return node.color==BLACK;
}
return false;
}
//3.4 设置结点为红 setRed(node)
private void setRed(RBNode node){
if(node != null){
node.color = RED;
}
}
//3.5 设置结点为黑 setBlack(node)
private void setBlack(RBNode node){
if(node != null){
node.color = BLACK;
}
}
//3.6 中序打印 isOrderPrint()
public void isOrderPrint(){
isOrderPrint(this.root); // 重载+递归
}
private void isOrderPrint(RBNode node){
if(node != null){
isOrderPrint(node.left); //先遍历左边 如果没有 就回来 输出中结点
System.out.println("key: "+node.key+" ,value: "+node.value);
isOrderPrint(node.right);
}
}
/**
* 4.1 左旋
* p p
* | |
* x y
* /\ --> /\
* lx y x ry
* /\ /\
* ly ry lx ly
*
* 1. 将ly转为x的右节点; ly的父结点为x
* 2. 将x的父结点p(若有)赋值成y的父节点; 父节点p的子结点为y(看是左是右)
* 3. x的父节点变成了y; y的左子结点变成x
*/
private void leftRotate(RBNode x){
if(x != null){
//先设左旋后的父节点为y
RBNode y = x.right;
//1. 将 ly转为x的右节点
x.right = y.left; //(x的右结点 -> ly)
//1. ly的父结点为x
if(y.left!=null) {
y.left.parent = x; //(ly的父节点 -> x)
}
//2.1 将x的父结点p(若有)赋值给y的父节点
if(x.parent!=null) {
y.parent = x.parent; //(y的父结点 -> p)
//2.2 父节点p的子结点为y //(p的子节点- >y)
if (x == x.parent.left) { //如果x是父节点的左结点
x.parent.left = y;
} else {
x.parent.right = y;
}
}else{ //x就是根结点
this.root = y; //y为根结点
y.parent = null;
}
//3.1 x的父节点变成y
x.parent = y; // (x的父结点 -> y)
//3.2 y的左子结点变成x
y.left = x; // (y的左结点 -> x)
}
}
/**
* 4.2 右旋
* p p
* | |
* x y
* /\ --> /\
* y rx ly x
* /\ /\
* ly ry ry rx
*
**/
private void rightRotate(RBNode x){
if(x != null){
//先设右旋后的父节点为y
RBNode y = x.left;
//1. 将 ry转为x的左节点
x.left = y.right; //(x的右结点 -> ly)
//1. ly的父结点为x
if(y.right!=null) {
y.right.parent = x; //(ly的父节点 -> x)
}
//2.1 将x的父结点p(若有)赋值给y的父节点
if(x.parent!=null) {
y.parent = x.parent; //(y的父结点 -> p)
//2.2 父节点p的子结点为y //(p的子节点- >y)
if (x == x.parent.left) { //如果x是父节点的左结点
x.parent.left = y;
} else {
x.parent.right = y;
}
}else{ //x就是根结点
this.root = y; //y为根结点
y.parent = null;
}
//3.1 x的父节点变成y
x.parent = y; // (x的父结点 -> y)
//3.2 y的左子结点变成x
y.right = x; // (y的左结点 -> x)
}
}
//5. 公开插入 insert(K key,V value)
public void insert(K key,V value){
RBNode node = new RBNode();
node.setKey(key);
node.setValue(value);
//新结点 一定是红色
node.setColor(RED);
insert(node);
}
//6. 内部插入 insert(RBNode node)
private void insert(RBNode node){
//查找父结点
RBNode parent = null;
RBNode p = this.root;
while(p!=null){
parent = p;
int cmp = node.key.compareTo(p.key);
if(cmp>0){
p = p.right;
}else if(cmp<0){
p = p.left;
}else{
p.setValue(node.getValue());
//不用说这个,因为是直接替换,所以这个key还是相同 他的父关系并没有变
//虽然parent改变了 但是他并没有将这个parent设置成自己的parent
//依旧是之前的parent
// node.parent = p.parent;
return;
//break;
}
}
//如果不是替换,而是添加到空白区域
node.parent = parent;
if(parent!=null){
int cmp = node.key.compareTo(parent.key);
if(cmp>0){
parent.right = node;
}else{
parent.left = node;
}
}else {
this.root = node;
}
//修复插入导致的平衡
insertFixUp(node);
}
/**
* 7. 修正插入导致的失衡 insertFixUp(RBNode node)
*
* 情景1. 空树: 根结点染黑
* 情景2. 要插入的结点key已经存在: 不需要处理
* 情景3. 插入结点的父结点为黑: 不用处理,依然平衡
* 情景4. 插入结点的父结点为红(爷爷为黑):
* 4.1 叔叔结点存在 且是红色(父叔双红)
* :将父叔染黑,并将爷爷染红,再将爷爷为当前结点,进行下一轮操作
* 4.2 叔叔为黑或不存在, 父是爷爷的左子树
* 4.2.1 插入结点是父的左子结点(LL) : 父染黑,爷爷染红,然后以爷爷为中心,右旋
* 4.2.2 插入结点是父的右子结点(LR) : 以父结点为中心,左旋,得到LL双红的情景(4.2.1),
* 然后以父为当前结点进行下一轮
* 4.3 叔叔为黑或不存在, 父是爷爷的右子树
* 4.3.1 插入结点是父的右子结点(RR) : 父染黑,爷爷染红,然后以爷爷为中心,左旋
* 4.3.2 插入结点是父的左子结点(RL) : 以父结点为中心,右旋,得到RR双红的情景(4.3.1),
* 然后以父为当前结点进行下一轮
*/
private void insertFixUp(RBNode node){
//情景1. 空树: 根结点染黑
this.root.setColor(BLACK);
RBNode parent = parentOf(node);
RBNode grandpa = parentOf(parent);
//情景4. 插入结点的父结点为红(爷爷为黑):爷爷一定不为空
if(parent!=null && isRed(parent)){
RBNode uncle = null;
if (parent == grandpa.left){ //父是左子树
uncle = grandpa.right;
//左右共有: 4.1叔叔结点存在 且是红色(父叔双红)
if(uncle!=null && isRed(uncle)){
//将父叔染黑,并将爷爷染红,再将爷爷为当前结点,进行下一轮操作
setBlack(parent);
setBlack(uncle);
setRed(grandpa);
insertFixUp(grandpa);
return;
}
//4.2 叔叔为黑或不存在, 父是爷爷的左子树
if(uncle==null || isBlack(uncle)){
//4.2.1 插入结点是父的左子结点(LL) : 父染黑,爷爷染红,然后以爷爷为中心,右旋
if(node==parent.left){
setBlack(parent);
setRed(grandpa);
rightRotate(grandpa);
return;
}
//4.2.2 插入结点是父的右子结点(LR) :
// 以父结点为中心,左旋,得到LL双红的情景(4.2.1),然后以父为当前结点进行下一轮
if(node==parent.right){
leftRotate(parent);
insertFixUp(parent);
return;
}
}
}else{ //父是右子树
uncle = grandpa.left;
//4.1叔叔结点存在 且是红色(父叔双红)
if(uncle!=null && isRed(uncle)){
//将父叔染黑,并将爷爷染红,再将爷爷为当前结点,进行下一轮操作
setBlack(parent);
setBlack(uncle);
setRed(grandpa);
insertFixUp(grandpa);
return;
}
//4.3 叔叔为黑或不存在, 父是爷爷的右子树
if(uncle==null || isBlack(uncle)){
//4.3.1 插入结点是父的右子结点(RR) : 父染黑,爷爷染红,然后以爷爷为中心,左旋
if(node==parent.right){
setBlack(parent);
setRed(grandpa);
leftRotate(grandpa);
return;
}
//4.3.2 插入结点是父的左子结点(RL) :
//以父结点为中心,右旋,得到RR双红的情景(4.3.1),然后以父为当前结点进行下一轮
if(node==parent.left){
rightRotate(parent);
insertFixUp(parent);
return;
}
}
}
}
}
//2 结点类
static class RBNode<K extends Comparable<K>, V>{
private RBNode left;
private RBNode right;
private RBNode parent;
private boolean color;
private K key;
private V value;
public RBNode getLeft() {
return left;
}
public void setLeft(RBNode left) {
this.left = left;
}
public RBNode getRight() {
return right;
}
public void setRight(RBNode right) {
this.right = right;
}
public RBNode getParent() {
return parent;
}
public void setParent(RBNode parent) {
this.parent = parent;
}
public boolean isColor() {
return color;
}
public void setColor(boolean color) {
this.color = color;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public RBNode() {
}
public RBNode(RBNode left, RBNode right, RBNode parent, boolean color, K key, V value) {
this.left = left;
this.right = right;
this.parent = parent;
this.color = color;
this.key = key;
this.value = value;
}
}
}