1. AVL树
AVL树简单来说是带有平衡条件的二叉查找树.传统来说是其每个节点的左子树和右子树的高度最多差1(注意不能只保持根节点平衡).
如上图所示,只有左边的才是AVL树,右图在7这个节点处平衡被破坏.
我们都知道,删除和插入意味着有可能打破平衡,如上图,将6插入的话在8位置的平衡将被打破.这意味着我们需要做一定的修正,称为旋转.
对于失去平衡有四种姿态,LL(左左),LR(左右),RR(右右)和RL(右左).下面分别给出示意图:
除了上面的情况之外,还有其它的失去平衡的AVL树,如下图:
上图只是易于理解,归根结底只有四种姿态:LL,LR,RR,RL.
对于LL与RR我们可以采取单旋转解决,而对于LR与RL我们得采取稍显复杂的双旋转.
-
单旋转
单旋转分为左左单旋转和右右单旋转
以上是左左单旋转的例子,比较简单不赘述
以上是右右单旋转的例子
-
双旋转
首先上图解释了为什么单旋转无法解决这种状况,解决这个问题的左右双旋转如下图所示:
首先我们把子树Y看成是一个节点两个子树构成的,这并不影响啥.仔细观察我们会发现,整个过程实际上是先让k1节点做一次右右单旋转,再做一次k3节点的左左单旋转.
右左双旋转如下图所示,原理类似不再赘述
-
AVL实现
AVL树的实现我们用代码来模拟:
package com.fredal.structure;
public class AVLTree<T extends Comparable<? super T>> {
//内部节点类
private static class AVLNode<T> {
T element;
AVLNode<T> left;//左孩子
AVLNode<T> right;//右孩子
int height;//当前高度
AVLNode(T theElement) {
this(theElement, null, null);
}
AVLNode(T theElement, AVLNode<T> lt, AVLNode<T> rt) {
element = theElement;
left = lt;
right = rt;
height = 0;
}
}
private AVLNode<T> root;//根节点
public AVLTree() {
root=null;
}
//插入
public void insert(T x){
root=insert(x,root);
}
//删除
public void remove(T x){
root=remove(x,root);
}
//寻找最小值
public T findMin(){
if(isEmpty())
throw new RuntimeException("空错误");
return findMin(root).element;
}
//寻找最大值
public T findMax(){
if(isEmpty())
throw new RuntimeException("空错误");
return findMax(root).element;
}
//是否存在
public boolean contains(T x){
return contains(x,root);
}
//清空
public void empty(){
root=null;
}
//判空
public boolean isEmpty(){
return root==null;
}
//打印树
public void printTree(){
if(isEmpty())
System.out.println("空树");
else
printTree(root);
}
//判断是否平衡
public void check(){
check(root);
}
//判断是否平衡
private int check(AVLNode<T> t) {
if(t==null)
return -1;
if(t!=null){
int hl=check(t.left);
int hr=check(t.right);
if(Math.abs(height(t.left)-height(t.right))>1||
height(t.left)!=hl||height(t.right)!=hr)
System.out.println("出错了");
}
return height(t);
}
//获取高度
private int height(AVLNode<T> t){
return t==null?-1:t.height;
}
//中序遍历
private void printTree(AVLNode<T> t) {
if(t!=null){
printTree(t.left);
System.out.println(t.element);
printTree(t.right);
}
}
//是否包含 递归遍历
private boolean contains(T x, AVLNode<T> t) {
while(t!=null){
int res=x.compareTo(t.element);
if(res<0)
t=t.left;
else if(res>0)
t=t.right;
else
return true;//找到了
}
return false;
}
//寻找最小值
private AVLNode<T> findMin(AVLNode<T> t) {
if(t==null)
return t;
while(t.left!=null)
t=t.left;
return t;
}
//寻找最大值
private AVLNode<T> findMax(AVLNode<T> t) {
if(t==null)
return t;
while(t.right!=null)
t=t.right;
return t;
}
//插入操作
private AVLNode<T> insert(T x, AVLNode<T> t) {
if(t==null)
return new AVLNode<T>(x, null, null);//插入当前的元素
int res=x.compareTo(t.element);
if(res<0)
t.left=insert(x, t.left);
else if(res>0)
t.right=insert(x, t.right);
else;//冲突了
return balance(t);//确保平衡
}
//删除操作
private AVLNode<T> remove(T x, AVLNode<T> t) {
if( t == null )
return t; // 啥也不做
int res = x.compareTo( t.element );
if( res < 0 )
t.left = remove( x, t.left );
else if( res > 0 )
t.right = remove( x, t.right );
else if( t.left != null && t.right != null ) //两个 孩子
{
t.element = findMin( t.right ).element;//寻找右子树最小的
t.right = remove( t.element, t.right );
}
else
t = ( t.left != null ) ? t.left : t.right;//一个孩子 这种情况只有一层
return balance( t );
}
//确保平衡状态
private AVLNode<T> balance(AVLNode<T> t) {
if(t==null)
return t;
if(height(t.left)-height(t.right)>1)//左子树比右子树深两层及以上
if(height(t.left.left)>=height(t.left.right))
t=singleRotateLL(t);//左左单旋转
else
t=doubleRotateLR(t);//左右双旋转
else
if(height( t.right ) - height( t.left )>1)//右子树比左子树深两层以上
if(height( t.right.right ) >= height( t.right.left ))//右右单旋转
t=singleRotateRR(t);
else
t=doubleRotateRL(t);//右左双旋转
t.height=Math.max(height(t.left), height(t.right))+1;
return t;
}
//右右单旋转
private AVLNode<T> singleRotateRR(AVLNode<T> k1) {
AVLNode<T> k2 = k1.right;
k1.right=k2.left;
k2.left=k1;
k1.height = Math.max( height( k1.left ), height( k1.right ) ) + 1;
k2.height = Math.max( height( k2.right ), k1.height ) + 1;
return k2;
}
//左左单旋转
private AVLNode<T> singleRotateLL(AVLNode<T> k2) {
AVLNode<T> k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
k2.height = Math.max( height( k2.left ), height( k2.right ) ) + 1;
k1.height = Math.max( height( k1.left ), k2.height ) + 1;
return k1;
}
//右左双旋转
private AVLNode<T> doubleRotateRL(AVLNode<T> k1) {
//右子树先左左单旋转
k1.right=singleRotateLL(k1.right);
return singleRotateRR(k1);//再整个右右单旋转
}
//左右双旋转
private AVLNode<T> doubleRotateLR(AVLNode<T> k3) {
//左子树先右右单旋转
k3.left=singleRotateRR(k3.left);
return singleRotateLL(k3);//再整个左左单旋转
}
public static void main(String[] args) {
AVLTree<Integer> tree=new AVLTree<Integer>();
for(int i=1;i<=7;i++){
tree.insert(i);
tree.check();
}
tree.printTree();
System.out.println("---------");
for(int i=10;i<=16;i++){
tree.insert(i);
tree.check();
}
tree.insert(8);
tree.insert(9);
tree.printTree();
System.out.println("----------");
System.out.println(tree.findMin());
System.out.println(tree.findMax());
System.out.println(tree.root.height);
System.out.println("--------------");
System.out.println("没有输出说明成功了...");
final int NUM=10000;
for(int i=37;i!=0;i=(i+37)%NUM){//随机插入
//System.out.println(i);
tree.insert(i);
}
for(int i=1;i<NUM;i+=2){//删除所有奇数
tree.remove(i);
}
for(int i=2;i<NUM;i+=2){
if(!tree.contains(i))
System.out.println("应该存在的偶数缺失");
}
for(int i=1;i<NUM;i+=2){
if(tree.contains(i))
System.out.println("不该存在的奇数存在");
}
}
}
可以看到测试类里我们使用了伪随机插入,这和线性同余稍有区别.足够大的随机数验证保证了AVL树的强壮.
2.伸展树
伸展树同样是一颗二叉查找树.对于AVL树而言,没插入一次就会呈现旋转,影响了插入和删除的效率,此时一个新的变种伸展树就被提出了.
它的优秀性能基于以下情况,如果我们每次都查询相同的节点或者频繁查询该节点,AVL树在节点越来越多的情况下呈现下旋,复杂度只会递增.而伸展树的想法就是,查询一个节点的时候就通过一些列类似AVL旋转把它顶到根节点.这样下次如果还是访问该节点,就特别方便.
基本上我们考虑以下两种状况,之字形与一字型.假设我们要查找X节点,那么:
以上是之字形旋转,可以看到,类似于AVL的双旋转.
还有一字型如下所示:
这种情况像是加强版的单旋转,需要做两次单旋转.
当然还有一种状况,就是纯粹的单旋转,比如X节点就是根节点的孩子,那么只要单旋转一次就行了.
接下来将自顶向下伸展树,这真是一种极好的实现方式,使得之字形与单旋转几乎不用工作,而一字型只需要一次单旋转即可,剩余的工作交给分离与合并即可.
上图即是三种情况分别对应的操作(单旋转查找Y,一字型查找Z,之字形查找Z),这种伸展方式把树分为L树,M树与R树,然后自顶向下查找元素,仅仅在一字型这种状况时候需要先进行单旋转操作预处理.比较目标与根节点的值,目标小就把根节点分离到R树,目标更大就把根节点分离到L树...一直到寻找到目标或者寻找到离目标最近的那个数.
分离到最后一层后,再进行合并操作即可:
上面即是自顶向下伸展树的伸展方法(查找)方法的全过程.我们得到的是刚好是目标,或者目标的前驱或后继.那么我们在执行插入操作的时候.仅仅是考虑插入数与根节点的大小关系插入即可,因为根节点的所有左子树必然小于插入数,根节点的右子树必然大于插入数.不用担心子树层及后面...
删除的逻辑同样很简单,不再赘述.
package com.fredal.structure; public class SplayTree<T extends Comparable<? super T>> {
//内部节点类
private static class BinaryNode<T>{
T element;
BinaryNode<T> left;//左子树
BinaryNode<T> right;//右子树
public BinaryNode(T element) {
this(element, null, null);
}
public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
this.element = element;
this.left = left;
this.right = right;
}
}
private BinaryNode<T> root;
private BinaryNode<T> nullNode;//表示null引用
private BinaryNode<T> newNode=null;//用于各种插入
private BinaryNode<T> header=new BinaryNode<T>(null);//用于展开 作为头节点
public SplayTree(){
nullNode=new BinaryNode<T>(null);
nullNode.left=nullNode.right=nullNode;
root=nullNode;
}
//插入操作 进行展开操作后 只要比较和根节点的大小进行一次操作即可
public void insert(T x){
if(newNode==null)
newNode=new BinaryNode<T>(null);
newNode.element=x;
if(root==nullNode){
newNode.left=newNode.right=nullNode;
root=newNode;
}
else{
root=splay(x,root);//伸展操作 将目标或者离目标最近的那个顶到根部
int res=x.compareTo(root.element);
if(res<0){
newNode.left=root.left;
newNode.right=root;
root.left=nullNode;
root=newNode;
}else if(res>0){
newNode.right=root.right;
newNode.left=root;
root.right=nullNode;
root=newNode;
}else
return;//重复了
}
newNode=null;
}
//删除操作
public void remove(T x){
if(!contains(x))//不包含 就返回
return;
BinaryNode<T> newTree;
root=splay(x, root);
if(root.left==nullNode)
newTree=root.right;//左边为空 直接右子树接上
else{
newTree=root.left;
newTree=splay(x, newTree);//找到左子树最大的作为根
newTree.right=root.right;
}
root=newTree;
}
//寻找最大值
public T findMax(){
if(isEmpty())
throw new RuntimeException("空了");
BinaryNode<T> t=root;
while(t.right!=nullNode)
t=t.right;//找到最大值
root=splay(t.element, root);//并伸展到根
return t.element;
}
//寻找最小值
public T findMin(){
if(isEmpty())
throw new RuntimeException("空了");
BinaryNode<T> t=root;
while(t.left!=nullNode)
t=t.left;//找到最小值
root=splay(t.element, root);//并伸展到根
return t.element;
}
//是否包含
public boolean contains(T x){
if(isEmpty())
return false;
root=splay(x, root);
return root.element.compareTo(x)==0;
}
//清空
public void empty(){
root=nullNode;
}
//判空
public boolean isEmpty(){
return root==nullNode;
}
//内部方法展开 找到一个刚好等于或者刚好大于或者刚好小于目标的数
private BinaryNode<T> splay(T x, BinaryNode<T> t) {
BinaryNode<T> leftTree,rightTree;//L R树
header.left=header.right=nullNode;
leftTree=rightTree=header;
nullNode.element=x;//保证匹配
for(;;){
int res=x.compareTo(t.element);
if(res<0){
//"一字型"旋转
if(x.compareTo(t.left.element)<0)
t=rotateL(t);
if(t.left==nullNode)
break;
//分离到R树 同时备份在header中
rightTree.left=t;
rightTree=t;
t=t.left;
}else if(res>0){
//"一字型旋转"
if(x.compareTo(t.right.element)>0)
t=rotateR(t);
if(t.right==nullNode)
break;
//分离到L树 同时备份在header中
leftTree.right=t;
leftTree=t;
t=t.right;
}else
break;
}
//最后一次分裂
leftTree.right=t.left;
rightTree.left=t.right;
//合并操作
//注意header.right相当于leftTree.right
t.left = header.right;
//header.left相当于righttree.left
t.right = header.left;
return t;
}
//右右单旋转
private BinaryNode<T> rotateR(BinaryNode<T> k1) {
BinaryNode<T> k2 = k1.right;
k1.right=k2.left;
k2.left=k1;
return k2;
}
//左左单旋转
private BinaryNode<T> rotateL(BinaryNode<T> k2) {
BinaryNode<T> k1 = k2.left;
k2.left=k1.right;
k1.right=k2;
return k1;
}
public static void main(String[] args) {
SplayTree<Integer> tree=new SplayTree<Integer>();
final int NUM=40000;
System.out.println("如果程序不输出就成功了....");
for(int i=37;i!=0;i=(i+37)%NUM)
tree.insert(i);//伪随机
for(int i=1;i<NUM;i+=2)
tree.remove(i);//删除所有奇数
if( tree.findMin( ) != 2 || tree.findMax( ) != NUM - 2 )
System.out.println( "最大值最小值寻找错误!" );
for( int i = 2; i < NUM; i += 2 )
if( !tree.contains( i ) )
System.out.println( "偶数缺失" + i );
for( int i = 1; i < NUM; i += 2 )
if( tree.contains( i ) )
System.out.println( "奇数多余" + i );
}
}
总结伸展树就是一个"顶"字.
3.红黑树
红黑树不愧是最难的数据结构之一...
R-B Tree,红黑树,同样是一颗特殊的二叉查找树变种.
红黑树拥有四大性质:
- 每个节点或者是红色,或者是黑色.
- 根是黑色的
- 如果一个节点是红色的,那么其子节点必须是黑色的.
- 从一个节点到一个null引用(即逻辑末尾)的每一条路径必须包含相同数目的黑色节点.
我们用双圈表示红色,一个例子如下:
红黑树的复杂度为(O log(N)),效率十分高,应用十分广泛,如java中的TreeSet,TreeMap,Linux虚拟内存管理.
-
复杂度相关证明
首先我们将会证明一颗含有n个节点的红黑树高度至多为2log(n+1).这个命题将保证查找操作是一种对数的操作,复杂度为O(log n).
然后上述命题的逆否命题为"高度为h的红黑树,它的包含的内节点个数至少为 2h/2-1个".我们只需证明这个就行
从某个节点x出发(不包括该节点)到达一个叶节点的任意一条路径上,黑色节点的个数称为该节点的黑高度(x's black height),记为bh(x).关于bh(x),我们可以得到两点:
a. 根据特性4,即从一个节点到一个null引用(即逻辑末尾)的每一条路径必须包含相同数目的黑色节点.得知bh(x)是唯一的.
b. 根据特性3.即如果一个节点是红色的,那么其子节点必须是黑色的.得知bh(x)≥h/2.进而得到证明"高度为h的红黑树,它包含的黑节点个数至少为2bh(x)-1个"即可.
接下来通过"数学归纳法"证明上述结论.
- 树的高度为0,bh(x)为0,2bh(x)-1为0.命题成立.
- 假设,当树高度为h-1,它包含的个数至少为2bh(x)-1-1.成立.
当树的高度为h的时候,根节点x的左右子树,高度为h-1,黑高度为bh(x)或bh(x)-1.
则节点x所包含的节点至少是 ( 2bh(x)-1-1 ) + ( 2bh(x)-1-1 )+1 = 2bh(x)-1.原命题成立.
-
插入
首先我们讲旋转时候都用avl树的术语,和红黑树的旋转正好相反,讲的各种情况的镜像也不再赘述...
这里是分为自底向上插入和自顶向下插入.首先默认n为当前点,p为父节点,g为祖父节点,u为叔叔节点,t为兄弟节点,先讲自底向上的插入:
- 如果插入的是根节点,那么直接把此节点涂黑
- 插入的节点的父亲是黑色的,啥也不做.
-
n的叔叔即u是红色的,这时候需要递归,我们在g上进行递归
-
u是黑色的,n是右孩子,对p进行右右单旋转变到状态5
-
u是黑色的,n是左孩子,对g点左左单旋转
情况3使得自底向上插入需要增加父亲指针,结构体变大,编程特麻烦.
所以我们考虑用自顶向下插入实现,一个思路就是,使得u永远是黑色的,就是避免了情况3的出现.
首先一种情况是碰到当前节点有两个红儿子,那么就需要翻转两个孩子和当前节点的颜色即可.如下:
这种情况只有在n的父节点也是红色的时候才会冲突,同时我们可以保证叔叔节点u一定是黑色的.那么自然而然可以参考上面的情况4与5解决问题.
-
删除
同样有自底向上和自顶向下两种,算法导论以及大部分的博客都写的自底向上的删除.这种方法要分好多种情况,而且比较难理解,我自己看得云里雾里.具体可以参考(http://blog.csdn.net/v_JULY_v/article/details/6105630) ,有六篇...
我还是来讲讲自顶向下删除,相对容易理解而且编码简单,虽然也蛮复杂.
首先可以分为两个大类A和B,然后我们按步骤step区分顺序.实在不想画图,网上找了图,白色代表红色,黑色代表黑色.x为当前节点,p为父节点,t为兄弟节点
Step1:
Step1A:表示x的两个孩子都是黑色的,下面分为三种情况
Step1A1:T有两个黑色的孩子,p,x,t节点变色
Step1A2:T有一个红色的左孩子,x,p变色,右左双旋转:
Step1A3:T有一个红色的右孩子,或者两个都是红色(这个放在上面也行的),这个..一字型旋转.x,p,t,r都变色
现在我们得到了红色的x节点,开始判断:
Step1_2A:
Step1_2A1:不是要删除的节点:继续下降,回到Step1初始阶段
Step1_2A2:是要删除的节点:判断是不是叶子节点.如果是就直接删除.不是的话,就要用右子树上的最小值或者左子树上的最大值代替x节点中的值.同时往右下或者左下降,回到Step1...
接下来是B情况了
Step1B:x至少有一个红色的孩子,这里我们先判断x是否是要找的值
Step1_2B1:x是要找的值:除了不用判断是不是叶子节点外,和Step1_2A2相同...
Step1_2B2:x不是:那么继续下降,分为两种情况,落在红孩子或者黑孩子上
Step1_2B2_1:落在红色的节点上,回到Step1_2A.
Step1_2B2_2:落在黑色的节点上
把上面那幅图的情况变成下面那副图的情况,p,t变色,p右右单旋转.然后转到了Step1A,或者Step1B.
我们以及完成了把当前节点变成红色,并且达到叶子节点删除的过程.
Step2:把根节点染成黑色
-
自顶向下红黑树的实现
删除和插入都是采用自顶向下的,其实编码有非常多要注意的地方.
package com.fredal.structure;
import javax.print.attribute.standard.Finishings;
import javax.swing.border.Border;
public class RedBlackTree<T extends Comparable<? super T>> {
// 内部节点类
private static class RedBlackNode<T> {
T element;
RedBlackNode<T> left;
RedBlackNode<T> right;
int color;// 颜色
public RedBlackNode(T element) {
this(element, null, null);
}
public RedBlackNode(T element, RedBlackNode<T> left,
RedBlackNode<T> right) {
this.element = element;
this.left = left;
this.right = right;
color = RedBlackTree.BLACK;
}
}
private static RedBlackNode header;// 头结点
private static RedBlackNode nullNode;// 逻辑空节点
private static final int BLACK = 1;
private static final int RED = 0;
private static RedBlackNode current;
private static RedBlackNode parent;
private static RedBlackNode grand;
private static RedBlackNode great;// 曾祖父
private static RedBlackNode brother;// 兄弟节点
public RedBlackTree() {
nullNode = new RedBlackNode<T>(null);
nullNode.left = nullNode.right = nullNode;
header = new RedBlackNode<T>(null);
header.left = header.right = nullNode;// 初始化
}
// 自顶向下插入
public void insert(T item) {
current = parent = grand = header;// 初始化
nullNode.element = item;
while (compare(item, current) != 0) {
great = grand;
grand = parent;
parent = current;
current = compare(item, current) < 0 ? current.left : current.right;
// 如果有两个红孩子 进行处理
if (current.left.color == RED && current.right.color == RED)
handleReorient(item);
}
if (current != nullNode)// 重复了
return;
current = new RedBlackNode<T>(item, nullNode, nullNode);// 插入节点
if (compare(item, parent) < 0)
parent.left = current;
else
parent.right = current;
handleReorient(item);// 处理一下叶子 左右两个null引用染黑
}
// 处理操作
private void handleReorient(T item) {
// 染色
current.color = RED;
current.left.color = BLACK;
current.right.color = BLACK;
if (parent.color == RED) {// 只有这种情况需要翻转
grand.color = RED;
if ((compare(item, grand) < 0) != (compare(item, parent) < 0))// 之字形
rotate(item, grand);// 先变成一字型
current = rotate(item, great);
current.color = BLACK;
}
header.right.color = BLACK;// 根节点染黑
}
private RedBlackNode<T> rotate(T item, RedBlackNode<T> parent) {
if (compare(item, parent) < 0)
// 返回旋转后的根节点
return parent.left = compare(item, parent.left) < 0 ?
rotateL(parent.left): // LL旋转
rotateR(parent.left);// LR旋转
else
return parent.right = compare(item, parent.right) < 0 ?
rotateL(parent.right): // RL旋转
rotateR(parent.right);// RR旋转
}
// 右右单旋转
private static RedBlackNode rotateR(RedBlackNode k1) {
RedBlackNode k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
return k2;
}
// 左左单旋转
private static RedBlackNode rotateL(RedBlackNode k2) {
RedBlackNode k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
return k1;
}
private int compare(T item, RedBlackNode<T> t) {
if (t == header)// 由于我们把header.right作为根
return 1;
else
return item.compareTo(t.element);
}
// 清空
public void makeEmpty() {
header.right = nullNode;
}
// 判空
public boolean isEmpty() {
return header.right == nullNode;
}
// 寻找最大值
public T findMax() {
if (isEmpty())
throw new RuntimeException("这是空树");
RedBlackNode<T> itr = header.right;
while (itr.right != nullNode)
itr = itr.right;
return itr.element;
}
// 寻找最小值
public T findMin() {
if (isEmpty())
throw new RuntimeException("这是空树");
RedBlackNode<T> itr = header.right;
while (itr.left != nullNode)
itr = itr.left;
return itr.element;
}
// 寻找值
public RedBlackNode<T> find(T x, RedBlackNode<T> t) {
RedBlackNode<T> parent = nullNode;
while (t != nullNode && t.element != x) {
parent = t;
if (x.compareTo(t.element) < 0)
t = t.left;
else
t = t.right;
}
if (t == nullNode)
return parent;
else
return t;
}
// 是否包含
public boolean contains(T x) {
nullNode.element = x;
current = header.right;
for (;;) {
if (x.compareTo((T) current.element) < 0)
current = current.left;
else if (x.compareTo((T) current.element) > 0)
current = current.right;
else if (current != nullNode)
return true;
else
return false;
}
}
// 打印树
public void printTree() {
if (isEmpty())
System.out.println("这是课空树");
else
printTree(header.right,0);
}
// 中序遍历
private void printTree(RedBlackNode<T> t,int depth) {
if (t != nullNode) {
printTree(t.left,depth+1);
for(int i=0;i<depth;i++)
System.out.print(" ");
System.out.println(t.element + ":"
+ (t.color == 1 ? "black" : "red"));
printTree(t.right,depth+1);
}
}
// 删除节点
public void remove(T item) {
header.color = RED;
current = header.right;
brother = header.left;
grand = great = parent = header;
while (current != nullNode) {
// 1A
if (current.left.color == BLACK && current.right.color == BLACK) {
// 1A1
if (brother.left.color == BLACK && brother.right.color == BLACK) {
parent.color = BLACK;
current.color = RED;
if(brother!=nullNode)
brother.color = RED;
}
// 要考虑镜像
else {
solve1A23();
}
// 完成染色current为红色 父节点为黑色 开始判断
if (current.element == item)
item = findItem(item);// 完成前进或者完成删除
else
normalDown(item);// 继续下降
} else {// 1B
// 先进行判断
if (current.element != item)
normalDown(item);// 下降
else
item = findItem(item);
if (current == nullNode)
break;
// 已经完成下降
if (current.color == BLACK) {// 下降到黑色
solve1B();
} else if (current.element != item)// 下降到红色 不是要找的 继续下降
normalDown(item);
else
item = findItem(item);
}
}
// 2
header.color = BLACK;
header.right.color = BLACK;// 复原
}
//解决1A2和1A3
private static void solve1A23(){
if (parent.left == current) {// 左孩子
if (brother.left.color == RED) {// 1A2
current.color = RED;
parent.color = BLACK;
parent.right = rotateL(brother);
if (grand.right == parent)
grand.right = rotateR(parent);
else
grand.left = rotateR(parent);
} else {// 1A3
current.color = RED;
parent.color = BLACK;
brother.color = RED;
brother.right.color = BLACK;
if (grand.right == parent)
grand.right = rotateR(parent);
else
grand.left = rotateR(parent);
}
} else {// 右孩子 镜像操作
if (brother.right.color == RED) {// 1A2
current.color = RED;
parent.color = BLACK;
parent.left = rotateR(brother);
if (grand.left == parent)
grand.left = rotateL(parent);
else
grand.right = rotateL(parent);
} else {// 1A3
current.color = RED;
parent.color = BLACK;
brother.color = RED;
brother.left.color = BLACK;
if (grand.right == parent)
grand.right = rotateL(parent);
else
grand.left = rotateL(parent);
}
}
}
//解决1B情况
private static void solve1B(){
brother.color = BLACK;
parent.color = RED;
if (parent.left == current) {
if (grand.left == parent)
grand.left = rotateR(parent);
else
grand.right = rotateR(parent);
brother = parent.right;
} else {// 镜像
if (grand.left == parent)
grand.left = rotateL(parent);
else
grand.right = rotateL(parent);
brother = parent.left;
}
}
// 下降
private void normalDown(T item) {
if (compare(item, current) < 0) {
grand = parent;
parent = current;
brother = parent.right;
current = current.left;
} else {
grand = parent;
parent = current;
brother = parent.left;
current = current.right;
}
}
private T findItem(T item) {
T temp;
RedBlackNode<T> toDelete;
// 先判断是否是叶子节点
if (current.left == nullNode && current.right == nullNode) {
if (parent.right == current)// 左孩子
parent.right = nullNode;
else
parent.left = nullNode;
current = nullNode;
temp = item;
} else {// 不是叶子节点
if (current.right != nullNode) {// 右子树找一个最小的
toDelete = find(item, current.right);
current.element = toDelete.element;
temp = toDelete.element;
if (toDelete.color == RED) {// 找到的是红色节点
current.right = deleteNode(toDelete, current.right);
current = nullNode;
} else {
grand = parent;
parent = current;
brother = parent.left;
current = current.right;//下降循环直到叶子
}
} else {// 从左子树找一个最大的
toDelete = find(item, current.left);
current.element = toDelete.element;
temp = toDelete.element;
if (toDelete.color == RED) {// 找到的是红色节点
current.left = deleteNode(toDelete, current.left);
current = nullNode;
} else {
grand = parent;
parent = current;
brother = parent.right;
current = current.left;//下降循环直到叶子
}
}
}
return temp;
}
// 删除节点
private RedBlackNode<T> deleteNode(RedBlackNode<T> target, RedBlackNode<T> t) {
RedBlackNode<T> origin = t;
RedBlackNode<T> parent = nullNode;
while (t != target) {
parent = t;
if (target.element.compareTo(t.element) < 0)
t = t.left;
else
t = t.right;
}
if (t == origin) {
RedBlackNode<T> temp;
if (t.right != nullNode)
temp = t.right;
else
temp = t.left;
return temp;
}
if (parent.right == t) {
if (t.right != nullNode)
parent.right = t.right;
else
parent.right = t.left;
} else {
if (t.right != nullNode)
parent.left = t.right;
else
parent.left = t.left;
}
return origin;
}
public static void main(String[] args) {
RedBlackTree<Integer> t = new RedBlackTree<Integer>();
t.insert(10);
t.insert(85);
t.insert(15);
t.insert(70);
t.insert(20);
t.insert(60);
t.insert(30);
t.insert(50);
t.insert(65);
t.insert(80);
t.insert(90);
t.insert(40);
t.insert(5);
t.insert(55);
t.insert(45);
t.printTree();
System.out.println();
t.remove(30);
t.printTree();
System.out.println();
t.remove(40);
t.printTree();
System.out.println();
t.remove(5);
t.printTree();
System.out.println();
t.remove(70);
t.printTree();
System.out.println();
t.remove(90);
t.printTree();
System.out.println();
t.remove(85);
t.printTree();
System.out.println();
t.remove(20);
t.printTree();
System.out.println();
t.remove(45);
t.printTree();
System.out.println();
t.remove(50);
t.printTree();
System.out.println();
t.remove(55);
t.printTree();
System.out.println();
t.remove(60);
t.printTree();
System.out.println();
System.out.println();
t.remove(80);
t.printTree();
System.out.println();
t.remove(10);
t.printTree();
System.out.println();
t.remove(15);
t.printTree();
System.out.println();
}
}