一.简介
红黑树作为一种二叉搜索树的一种实现,红黑树的左右子树高度差可能大于 1。所以红黑树不是严格意义上的平衡二叉树(AVL),但红黑树是黑色节点完美平衡, 其平均统计性能要强于 AVL 。
红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。
1.节点是红色或黑色。
2.根节点是黑色。
3.每个红色节点的两个子节点都是黑色。(红色节点的子节点必须是黑色节点)
4.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
故红黑树是黑色平衡的树,左子树与右子树高度差不会超过2倍。红节点的父节点、子节点只能是黑节点
如果插入节点是黑色则所在路径将多出一个黑色节点,故新插入节点是红色节点(插入/删除红色节点不会改变所在路径黑色节点数量),通过旋转和调整节点颜色保证树的平衡
二.实现
红黑树增加/删除节点时需要保证子树黑节点平衡,有如下情况:
1.插入节点为树的根节点时,把根节点颜色修改为黑色
2.插入节点父节点是黑色节点,由于插入节点是红色节点,不会影响该子树黑色节点数量,故不用任何处理
3.插入节点父节点为红色且父节点的兄弟节点也为红色,父节点、父节点的兄弟节点修改为黑色,父节点的父节点修改为红色,再以父节点的父节点为插入节点递归处理
4.父节点为红色且父节点的兄弟节点为null或为黑节点
由于父节点是红色节点,故父节点的父节点为黑色节点
1)LL型
插入数据父节点的兄弟节点只会为null,如果不为null则父节点的兄弟节点子树与父节点将不是平衡的。
修改父节点为黑色节点,祖父节点修改为红色节点
对祖父节点右旋转,让父节点为子树根节点,由于子树黑节点数量没有发生变化,故旋转后黑节点数量和旋转前一样
2)LR型
父节点左旋转将变为LL型,按LL型处理
3)RR型
修改父节点为黑色,祖父节点修改为红色,对祖父节点左旋转,让父节点为子树根节点,旋转后和旋转前黑色节点数量没有改变,故事黑色节点平衡
4)RL型
父节点右旋转变为RR型,按RR型处理
示例说明:
插入数据:4,3,6,5,7,8,9,10,11
package com.vincent;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
RBTree tree = new RBTree<>();
for(Integer data : Arrays.asList(4,3,6,5,7,8,9,10,11)){
tree.add(data);
System.out.println(tree.getRoot());
}
System.out.println();
List list = tree.infixList();
System.out.println(list);
tree.delete(list.get(0));
list = tree.infixList();
System.out.println(list);
tree.delete(list.get(list.size()-1));
list = tree.infixList();
System.out.println(list);
tree.delete(list.get(list.size()/2));
list = tree.infixList();
System.out.println(list);
}
}
//红黑树
class RBTree<T extends Comparable>{
private static final int RED = 0;
private static final int BLACK = 1;
static class Node<T extends Comparable<T>> {
private T item;
private int color = RED;
private Node<T> left;
private Node<T> right;
private Node<T> parent;
public Node(T item) {
this.item = item;
}
public T getItem(){
return item;
}
/**
* 添加节点到当前节点树
* @param node 添加的节点
*/
public void add(Node<T> node){
if(node.item.compareTo(this.item) <= 0){
if(this.left == null){
this.left = node;
node.parent = this;
}