【数据结构】平衡二叉树的插入、删除

目录

定义:什么叫平衡二叉树

定义及原理 

不平衡的四种情况

旋转操作

插入节点

 删除节点

 

定义:什么叫平衡二叉树

是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树。1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵树,所以它又叫AVL树。平衡二叉树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。

《【数据结构】平衡二叉树的插入、删除》

定义及原理 

现在又a[8] = {1,2,3,4,5,6,7,8}需要构建二叉排序树。在没有学习平衡二叉树之前,根据二叉排序树的特性,通常会将它构建成如下左图。虽然完全符合二叉排序树的定义,但是对这样高度达到8的二叉树来说,查找是非常不利的。因此,更加期望构建出如下右图的样子,高度为4的二叉排序树,这样才可以提供高效的查找效率。 

《【数据结构】平衡二叉树的插入、删除》

不平衡的四种情况

《【数据结构】平衡二叉树的插入、删除》

  1. 6节点的左子树3节点高度比右子树7节点大2,左子树3节点的左子树1节点高度大于右子树4节点,这种情况成为左左。
  2. 6节点的左子树2节点高度比右子树7节点大2,左子树2节点的左子树1节点高度小于右子树4节点,这种情况成为左右。
  3. 2节点的左子树1节点高度比右子树5节点小2,右子树5节点的左子树3节点高度大于右子树6节点,这种情况成为右左。
  4. 2节点的左子树1节点高度比右子树4节点小2,右子树4节点的左子树3节点高度小于右子树6节点,这种情况成为右右。

从图3中可以可以看出,1和4两种情况是对称的,这两种情况的旋转算法是一致的,只需要经过一次旋转就可以达到目标,我们称之为单旋转。2和3两种情况也是对称的,这两种情况的旋转算法也是一致的,需要进行两次旋转,我们称之为双旋转。

AVL数据结构

public class AVLTree {
	private class Node{
		int value;
		int bf;
		Node lchild;
		Node rchild;
		Node parent;
		public Node(int value,int bf,Node lchild,Node rchild,Node parent){
			this.value=value;
			this.bf=bf;
			this.lchild=lchild;
			this.rchild=rchild;
			this.parent=parent;
		}
	}
	Node root=null;                     //根节点
	final int LH =+1;                        /*  左高 */ 
	final int EH= 0;                            /*  等高 */ 
	final int RH=-1;                           /*  右高 */ 
	final int LC=0;                         //在左子树插入
	final int RC=1;							//在右子树插入
	final boolean FALSE=false;
	final boolean TRUE=true;
}

旋转操作

单旋转是针对于左左和右右这两种情况的解决方案,这两种情况是对称的,只要解决了左左这种情况,右右就很好办了。图3是左左情况的解决方案,节点k2不满足平衡特性,因为它的左子树k1比右子树Z深2层,而且k1子树中,更深的一层的是k1的左子树X子树,所以属于左左情况。

《【数据结构】平衡二叉树的插入、删除》

开始时,k2节点左孩子是小x,整棵树还是平衡树,然后在小x的子节点插入一个数,小x变成大X,此时大X高度为2,k1节点不平衡,为使树恢复平衡,我们把k2变成这棵树的根节点,因为k2大于k1,把k2置于k1的右子树上,而原本在k1右子树的Y大于k1,小于k2,就把Y置于k2的左子树上,这样既满足了二叉查找树的性质,又满足了平衡二叉树的性质。

这样的操作只需要一部分指针改变,结果我们得到另外一颗二叉查找树,它是一棵AVL树,因为X向上一移动了一层,Y还停留在原来的层面上,Z向下移动了一层。整棵树的新高度和之前没有在左子树上插入的高度相同,插入操作使得X高度长高了。因此,由于这颗子树高度没有变化,所以通往根节点的路径就不需要继续旋转了。

右旋转代码:

/* 对以T为根的二叉排序树作右旋处理 */
	/* 处理之后T的父节点指向T的左节点 */
	//右旋-顺时针旋转(如LL型就得对根结点做该旋转)
	private void R_Rotate(Node T)
	{ 
	    Node L,P;
	    P=T.parent;
	    L=T.lchild;                      /*  L指向node的左子树根结点 */
	    T.lchild=L.rchild;               /*  L的右子树挂接为node的左子树 */ 
	    
	    if(L.rchild!=null)
	    	L.rchild.parent=T;
	    L.rchild=T;
	    L.parent=P;
	    T.parent=L;
	    
	    if(P==null)
	    	root=L;
	    else if(P.rchild==T)
	    	P.rchild=L;
	    else
	    	P.lchild=L;
	    
	}

右旋转原理:获取失去平衡结点以及左结点,为了让lchild作为根节点,将lchild的rchild挂接到之前左结点上,然后在挂接到s->rchild.

左旋转代码

/* 对以T为根的二叉排序树作左旋处理, */
	/* 处理之后T的父节点指向T的右节点 */
	//左旋-逆时针旋转(如RR型就得对根结点做该旋转)
	private void L_Rotate(Node T)
	{ 
	    Node R,P;
	    P=T.parent;
	    R = T.rchild;                    /* R指向T的右子树根结点 */
	    T.rchild = R.lchild;         /* R的左子树挂接为T的右子树 */
	   
	    if(R.lchild!=null)
	    	R.lchild.parent=T;
	    R.lchild = T;
	    R.parent=P;
	    T.parent=R;
	    
	    if(P==null)
	    	root=R;
	    else if(P.rchild==T)
	    	P.rchild=R;
	    else
	    	P.lchild=R; 
	                       
	}

双旋转

对于左右和右左这两种情况,单旋转不能使它达到一个平衡状态,要经过两次旋转。双旋转是针对于这两种情况的解决方案,同样的,这样两种情况也是对称的,只要解决了左右这种情况,右左就很好办了。图4是左右情况的解决方案,节点k3不满足平衡特性,因为它的左子树k1比右子树Z深2层,而且k1子树中,更深的一层的是k1的右子树k2子树,所以属于左右情况。

《【数据结构】平衡二叉树的插入、删除》

为使树恢复平衡,我们需要进行两步,第一步,把k1作为根,进行一次z左旋转,旋转之后就变成了左左情况,所以第二步再进行一次右旋转,最后得到了一棵以k2为根的平衡二叉树树。

双旋转代码

/*  对以指针T所指结点为根的二叉树作左平衡旋转处理 */
	/*  本算法结束时,指针T指向新的根结点 */
	public void LeftBalance(Node T)
	{ 
	    Node L,Lr;
	    L = T.lchild;                    /*  L指向T的左子树根结点 */
	    switch(L.bf)
	    { 
	        /* 检查T的左子树的平衡度,并作相应平衡处理 */
	        case LH:                        /* 新结点插入在T的左孩子的左子树上,要作单右旋处理 */
	            T.bf=L.bf=EH;
	            R_Rotate(T);
	            break;
	        case RH:                        /* 新结点插入在T的左孩子的右子树上,要作双旋处理 */ //
	            Lr=L.rchild;                /* Lr指向T的左孩子的右子树根 */
	            switch(Lr.bf)
	            {   
	                /* 修改T及其左孩子的平衡因子 */
	                case LH: 
	                    T.bf=RH;
	                    L.bf=EH;
	                    break;
	                case EH: 
	                    T.bf=L.bf=EH;
	                    break;
	                case RH: 
	                    T.bf=EH;
	                    L.bf=LH;
	                    break;
	            }
	            Lr.bf=EH;
	            L_Rotate(T.lchild); /* 对T的左子树作左旋平衡处理 */
	            R_Rotate(T);                /* 对T作右旋平衡处理 */
	            break;
	        case EH:	  //特殊情况4,这种情况在添加时不可能出现,只在移除时可能出现,旋转之后整体树高不变
				L.bf = RH;
				T.bf = LH;
				R_Rotate(T);
				break;
	    }
	}

首先,定义三个常数变量,分别代码1、0、-1。

    (1)函数被调用,传入一个需调整平衡型的子树T,根节点为k3,由于LeftBalance函数被调用时,其实是已经确认当前子树是不平衡的状态,且左子树的高度大于右子树的高度。换句话说,此时T的根结点应该是平衡因子BF的值大于1的数。k3的BF为2

    (2)将T的左孩子赋值给L。L指向K1.

    (3)然后是分支判断。

    (4)当L(k1)的平衡因子为LH,即为1时,表明它与根结点的BF值符号相同,因此,将它们的BF值都改为0,并进行右旋(顺时针)操作,是左左情况

    (5)当L的平衡因子为RH时,即为-1时,表明它与根结点的BF值符号相反,此时需要做双旋操作。针对L的右孩子k2的BF作判断,修改结点T(k3)和L(k1)的BF值。将当前的Lr的BF改为0。从图中看到K2的左结点是连接到K1的右子树上,右结点连接到K3的左子树,其中当k2结点为RH,说明K2有右结点有,左结点无,k3为0((*T)->bf=EH; ),k1就没有右结点为LH。当为Lh看程序。

    (6)对根结点的左子树进行左旋,以K1为根节点进行左旋转,形成左左情况。

    (7)对根结点K3进行右旋,完成平衡操作。

插入节点

插入过程也是一个二叉树查找的过程,先看图

《【数据结构】平衡二叉树的插入、删除》

在插入节点2之前,该树还是一颗平衡树,当插入节点2之后,节点3就成为了不平衡点,需要对节点3进行左平衡处理。

在详细的分析一下:

首先从根节点4开始搜索,发现2<4,于是搜索4的左节点3,发现2<3,就搜索1,2>1,搜索1的右节点,此时发现1的右节点为空,就执行插入操作,将2插入到1的右节点,那么怎么发现此时这棵树不平衡的呢?因为我们是通过递归寻找插入点,当找到插入点在1的右节点之后,开始往父节点回溯,回溯过程中告诉父节点,孩儿有没有长高,如果长高了,父节点就要判断左右子树高度差是否大于1,也就是处于不平衡状态,每个节点都有个平衡因子,EH=0(等高),LH=1(左边高1),RH=-1(右边高1)例如,插入2之前,节点1的BF=0,节点3BF=1,节点4BF=1,插入节点2之后,往父节点1回溯,说我长高了,1节点BF=0,现在右节点长高了,所以此时节点1BF=-1,在往父节点3回溯,告诉父节点3,我长高了,而父节点3BF=1,而现在左孩子长高了,那BF=2,此时节点3称为不平衡点,需要对节点3做左平衡处理。处理完成后,2节点变成了1,3的父节点,此时2节点的高度和没插入节点2之前3节点高度一样,于是告诉父节点4,我没有长高,此时递归结束。

代码如下:

public void insertAVL(int e){
		if(root==null){
			root=new Node(e,EH,null,null,null);
			return;
		}
		TS t=new TS();
		InsertAVL(root,e,t,null);
	}
	/*  若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 */
	/*  数据元素为e的新结点,并返回1,否则返回0。若因插入而使二叉排序树 */
	/*  失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。 */
	private boolean InsertAVL(Node T,int e,TS tl,Node parent)
	{  
	    if(T==null)
	    { 
	        /*  插入新结点,树“长高”,置taller为TRUE */
	        Node nNode=new Node(e,EH,null,null,parent);
	        if(e<parent.value)
	        	parent.lchild=nNode;
	        else
	        	parent.rchild=nNode;
	        tl.taller=TRUE;
	    }
	    else
	    {
	        if (e==T.value)
	        { 
	            /*  树中已存在和e有相同关键字的结点则不再插入 */
	        	tl.taller=FALSE; 
	        	return false;
	        }
	        else if (e<T.value)
	        { 
	            /*  应继续在T的左子树中进行搜索 */
	            if(!InsertAVL(T.lchild,e,tl,T))
	            	return false;
	            if(tl.taller)                             /*   已插入到T的左子树中且左子树“长高” */
	                switch(T.bf)                 /*  检查T的平衡度 */
	                {
	                    case LH:                        /*  原本左子树比右子树高,需要作左平衡处理 */
	                        LeftBalance(T); 
	                        tl.taller=FALSE; 
	                        break;
	                    case EH:                        /*  原本左、右子树等高,现因左子树增高而使树增高 */
	                        T.bf=LH; 
	                        tl.taller=TRUE; 
	                        break;
	                    case RH:                        /*  原本右子树比左子树高,现左、右子树等高 */ 
	                        T.bf=EH; 
	                        tl.taller=FALSE; 
	                        break;
	                }
	        }
	        else
	        { 
	            /*  应继续在T的右子树中进行搜索 */
	            if(!InsertAVL(T.rchild,e,tl,T))
	            	return false;
	            if(tl.taller)                             /*  已插入到T的右子树且右子树“长高” */
	            {
	                switch(T.bf)                 /*  检查T的平衡度 */
	                {
	                    case LH:                        /*  原本左子树比右子树高,现左、右子树等高 */
	                        T.bf=EH; 
	                        tl.taller=FALSE;  
	                        break;
	                    case EH:                        /*  原本左、右子树等高,现因右子树增高而使树增高  */
	                        T.bf=RH; 
	                        tl.taller=TRUE; 
	                        break;
	                    case RH:                        /*  原本右子树比左子树高,需要作右平衡处理 */
	                        RightBalance(T); 
	                        tl.taller=FALSE; 
	                        break;
	                }
	            }
	        }
	    }
	    return true;
	}

 删除节点

删除操作和二叉查找树删除一样,分为三种情况讨论

(1)删除节点没有左子树,这种情况直接将删除节点的父节点指向删除节点的右子树。

(2)删除节点没有右子树,这种情况直接将删除节点的父节点指向删除节点的左子树。

(3)删除节点左右子树都存在,可以采用两种方式,

         1:让删除节点左子树的最右侧节点代替当前节点

         2:让删除节点右子树的最左侧节点代替当前节点

如下图:

《【数据结构】平衡二叉树的插入、删除》

这里的难点是删除之后要判断该树是否还平衡? 

还是先看图:

《【数据结构】平衡二叉树的插入、删除》

 和插入操作一样,删除操作也是递归查找,然后删除,删除之后,该节点A要向父节点回溯,告诉父节点B我变矮了(因为删除了),父节点B此时要判断自己是否也变矮了,如果删除的节点是自己的左子树中的节点(右子树同理,这里只讨论左子树情况,右子树请看代码),就要分三种情况讨论:

(1)B.BF=EH ,也就是原来B节点左右子树高度一致,而现在左子树告诉我,左子树变矮了,则需要将B.BF设置为RH,即右边高,同时可知B的高度并没变化,所以再往B的父节点C回溯的时候,B的父节点C就会当啥都没发生。

(2)B.BF=LH,也就是原来B节点左子树比右子树高一层而现在左子树告诉我,左子树变矮了,则需要将B.BF设置为EH,同时可知B节点的高度也变矮了,于是再往B的父节点C回溯的是否,C也要分三种情况讨论。

(3)B.BF=RH,也就是原来B节点右子树比左子树高一层,而现在左子树告诉我,左子树变矮了,则需要对B进行右平衡处理

而这里又要分为两种情况讨论来判断,右平衡处理完成后,需要判断B的父节点C的左子树是否变矮了

1.B.rchild.BF=EH,也就是B节点(右平衡处理之前)的右子树的左右子树等高。那么这种情况,B的父节点C的左子树不变矮。

2.除了1情况,B的父节点C的左子树会变矮。

下面画图来理解一下这两种情况。

《【数据结构】平衡二叉树的插入、删除》

这是第一种情况,6的右节点8的BF=EH,那么旋转后高度不变。

《【数据结构】平衡二叉树的插入、删除》

这是第二种情况,6的右节点8的BF!=EH,那么旋转后高度变矮。

删除代码如下:

/* 
若在平衡的二叉排序树t中存在和e有相同关键字的结点,则删除之 
并返回TRUE,否则返回FALSE。若因删除而使二叉排序树 
失去平衡,则作平衡旋转处理,布尔变量shorter反映t变矮与否
*/
private boolean deleteAVL(Node t, int key, TS ts)
{
    if(t == null)                                      //不存在该元素 
    {
        return FALSE;                                   //删除失败 
    }
    else if(key == t.value)                           //找到元素结点
    {
        Node q = null;
        if(t.lchild == null)                     //左子树为空 
        {
            q = t.parent;
            if(q==null)
            	root=t.rchild;
            else{
            	if(key<q.value)
            		q.lchild=t.rchild;
            	else
            		q.rchild=t.rchild;
            }
            ts.shorter = TRUE;
        }
        else if(t.rchild == null)                    //右子树为空 
        {
            q = t.parent;
            if(q==null)
            	root=t.lchild;
            else{
            	if(key<q.value)
            		q.lchild=t.lchild;
            	else
            		q.rchild=t.lchild;
            }
            ts.shorter = TRUE;
        }
        else                                            //左右子树都存在,
        {
            q = t.lchild;
            while(q.rchild!=null)
            {
                q = q.rchild;
            }
            t.value = q.value;
            deleteAVL(t.lchild, q.value, ts);   //在左子树中递归删除前驱结点 
        }
    }
    else if(key < t.value)                         //左子树中继续查找 
    {
        if(!deleteAVL(t.lchild, key, ts))
        {
            return FALSE;
        }
        if(ts.shorter)
        {
            switch(t.bf)
            {
            case LH:
                t.bf = EH;
                ts.shorter = TRUE;
                break;
            case EH:
                t.bf = RH;
                ts.shorter = FALSE;
                break;
            case RH:
            	 if(t.rchild.bf == EH)    //注意这里,画图思考一下 
                     ts.shorter = FALSE;
                 else
                     ts.shorter = TRUE;
                RightBalance(t);        //右平衡处理   
                break;
            }
        }
    }
    else                                //右子树中继续查找 
    {
        if(!deleteAVL(t.rchild, key, ts))
        {
            return FALSE;
        }
        if(ts.shorter)
        {
            switch(t.bf)
            {
            case LH:
            	 if(t.lchild.bf == EH)  //注意这里,画图思考一下 
                     ts.shorter = FALSE;
                 else
                     ts.shorter = TRUE;
                LeftBalance(t);         //左平衡处理 
                break;
            case EH:
                t.bf = LH;
                ts.shorter = FALSE;
                break;
            case RH:
                t.bf = EH;
                ts.shorter = TRUE;
                break;
            }
        }
    }
    return TRUE;
}

OK,到此二叉平衡树讲完了,后面把源码附上:

package wangyi;


public class AVLTree {
	private class Node{
		int value;
		int bf;
		Node lchild;
		Node rchild;
		Node parent;
		public Node(int value,int bf,Node lchild,Node rchild,Node parent){
			this.value=value;
			this.bf=bf;
			this.lchild=lchild;
			this.rchild=rchild;
			this.parent=parent;
		}
	}
	Node root=null;
	final int LH =+1;                        /*  左高 */ 
	final int EH= 0;                            /*  等高 */ 
	final int RH=-1;                           /*  右高 */ 
	final int LC=0;                         //在左子树插入
	final int RC=1;							//在右子树插入
	final boolean FALSE=false;
	final boolean TRUE=true;
	
	/* 对以T为根的二叉排序树作右旋处理 */
	/* 处理之后T的父节点指向T的左节点 */
	//右旋-顺时针旋转(如LL型就得对根结点做该旋转)
	private void R_Rotate(Node T)
	{ 
	    Node L,P;
	    P=T.parent;
	    L=T.lchild;                      /*  L指向node的左子树根结点 */
	    T.lchild=L.rchild;               /*  L的右子树挂接为node的左子树 */ 
	    
	    if(L.rchild!=null)
	    	L.rchild.parent=T;
	    L.rchild=T;
	    L.parent=P;
	    T.parent=L;
	    
	    if(P==null)
	    	root=L;
	    else if(P.rchild==T)
	    	P.rchild=L;
	    else
	    	P.lchild=L;
	    
	}
	 
	/* 对以T为根的二叉排序树作左旋处理, */
	/* 处理之后T的父节点指向T的右节点 */
	//左旋-逆时针旋转(如RR型就得对根结点做该旋转)
	private void L_Rotate(Node T)
	{ 
	    Node R,P;
	    P=T.parent;
	    R = T.rchild;                    /* R指向T的右子树根结点 */
	    T.rchild = R.lchild;         /* R的左子树挂接为T的右子树 */
	   
	    if(R.lchild!=null)
	    	R.lchild.parent=T;
	    R.lchild = T;
	    R.parent=P;
	    T.parent=R;
	    
	    if(P==null)
	    	root=R;
	    else if(P.rchild==T)
	    	P.rchild=R;
	    else
	    	P.lchild=R; 
	                       
	}

	/*  对以指针T所指结点为根的二叉树作左平衡旋转处理 */
	/*  本算法结束时,指针T指向新的根结点 */
	public void LeftBalance(Node T)
	{ 
	    Node L,Lr;
	    L = T.lchild;                    /*  L指向T的左子树根结点 */
	    switch(L.bf)
	    { 
	        /* 检查T的左子树的平衡度,并作相应平衡处理 */
	        case LH:                        /* 新结点插入在T的左孩子的左子树上,要作单右旋处理 */
	            T.bf=L.bf=EH;
	            R_Rotate(T);
	            break;
	        case RH:                        /* 新结点插入在T的左孩子的右子树上,要作双旋处理 */ //
	            Lr=L.rchild;                /* Lr指向T的左孩子的右子树根 */
	            switch(Lr.bf)
	            {   
	                /* 修改T及其左孩子的平衡因子 */
	                case LH: 
	                    T.bf=RH;
	                    L.bf=EH;
	                    break;
	                case EH: 
	                    T.bf=L.bf=EH;
	                    break;
	                case RH: 
	                    T.bf=EH;
	                    L.bf=LH;
	                    break;
	            }
	            Lr.bf=EH;
	            L_Rotate(T.lchild); /* 对T的左子树作左旋平衡处理 */
	            R_Rotate(T);                /* 对T作右旋平衡处理 */
	            break;
	        case EH:	  //特殊情况4,这种情况在添加时不可能出现,只在移除时可能出现,旋转之后整体树高不变
				L.bf = RH;
				T.bf = LH;
				R_Rotate(T);
				break;
	    }
	}
	 
	/*  对以指针T所指结点为根的二叉树作右平衡旋转处理, */
	/*  本算法结束时,指针T指向新的根结点 */
	public void RightBalance(Node T)
	{ 
	    Node R,Rl;
	    R=T.rchild;                      /*  R指向T的右子树根结点 */
	    switch(R.bf)
	    { 
	        /*  检查T的右子树的平衡度,并作相应平衡处理 */
	        case RH:                        /*  新结点插入在T的右孩子的右子树上,要作单左旋处理 */
	            T.bf=R.bf=EH;
	            L_Rotate(T);
	            break;
	        case LH:                        /*  新结点插入在T的右孩子的左子树上,要作双旋处理 */ //最小不平衡树的根结点为负,其右孩子为正
	            Rl=R.lchild;                /*  Rl指向T的右孩子的左子树根 */
	            switch(Rl.bf)
	            { 
	                /*  修改T及其右孩子的平衡因子 */
	                case RH: 
	                    T.bf=LH;
	                    R.bf=EH;
	                    break;
	                case EH: 
	                    T.bf=R.bf=EH;
	                    break;
	                case LH: 
	                    T.bf=EH;
	                    R.bf=RH;
	                    break;
	            }
	            Rl.bf=EH;
	            R_Rotate(T.rchild); /*  对T的右子树作右旋平衡处理 */
	            L_Rotate(T);                /*  对T作左旋平衡处理 */
	            break;
	        case EH:	  //特殊情况4,这种情况在添加时不可能出现,只在移除时可能出现,旋转之后整体树高不变
				R.bf = LH;
				T.bf = RH;
				L_Rotate(T);
				break;

	    }
	}
	
	
	public void insertAVL(int e){
		if(root==null){
			root=new Node(e,EH,null,null,null);
			return;
		}
		TS t=new TS();
		InsertAVL(root,e,t,null);
	}
	/*  若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 */
	/*  数据元素为e的新结点,并返回1,否则返回0。若因插入而使二叉排序树 */
	/*  失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。 */
	private boolean InsertAVL(Node T,int e,TS tl,Node parent)
	{  
	    if(T==null)
	    { 
	        /*  插入新结点,树“长高”,置taller为TRUE */
	        Node nNode=new Node(e,EH,null,null,parent);
	        if(e<parent.value)
	        	parent.lchild=nNode;
	        else
	        	parent.rchild=nNode;
	        tl.taller=TRUE;
	    }
	    else
	    {
	        if (e==T.value)
	        { 
	            /*  树中已存在和e有相同关键字的结点则不再插入 */
	        	tl.taller=FALSE; 
	        	return false;
	        }
	        else if (e<T.value)
	        { 
	            /*  应继续在T的左子树中进行搜索 */
	            if(!InsertAVL(T.lchild,e,tl,T))
	            	return false;
	            if(tl.taller)                             /*   已插入到T的左子树中且左子树“长高” */
	                switch(T.bf)                 /*  检查T的平衡度 */
	                {
	                    case LH:                        /*  原本左子树比右子树高,需要作左平衡处理 */
	                        LeftBalance(T); 
	                        tl.taller=FALSE; 
	                        break;
	                    case EH:                        /*  原本左、右子树等高,现因左子树增高而使树增高 */
	                        T.bf=LH; 
	                        tl.taller=TRUE; 
	                        break;
	                    case RH:                        /*  原本右子树比左子树高,现左、右子树等高 */ 
	                        T.bf=EH; 
	                        tl.taller=FALSE; 
	                        break;
	                }
	        }
	        else
	        { 
	            /*  应继续在T的右子树中进行搜索 */
	            if(!InsertAVL(T.rchild,e,tl,T))
	            	return false;
	            if(tl.taller)                             /*  已插入到T的右子树且右子树“长高” */
	            {
	                switch(T.bf)                 /*  检查T的平衡度 */
	                {
	                    case LH:                        /*  原本左子树比右子树高,现左、右子树等高 */
	                        T.bf=EH; 
	                        tl.taller=FALSE;  
	                        break;
	                    case EH:                        /*  原本左、右子树等高,现因右子树增高而使树增高  */
	                        T.bf=RH; 
	                        tl.taller=TRUE; 
	                        break;
	                    case RH:                        /*  原本右子树比左子树高,需要作右平衡处理 */
	                        RightBalance(T); 
	                        tl.taller=FALSE; 
	                        break;
	                }
	            }
	        }
	    }
	    return true;
	}
	public boolean deleteAVL(int key){
		if(root==null)
			throw new RuntimeException("这是空树!");
		TS ts=new TS();
		return deleteAVL(root,key,ts);
	}

/* 
若在平衡的二叉排序树t中存在和e有相同关键字的结点,则删除之 
并返回TRUE,否则返回FALSE。若因删除而使二叉排序树 
失去平衡,则作平衡旋转处理,布尔变量shorter反映t变矮与否
*/
private boolean deleteAVL(Node t, int key, TS ts)
{
    if(t == null)                                      //不存在该元素 
    {
        return FALSE;                                   //删除失败 
    }
    else if(key == t.value)                           //找到元素结点
    {
        Node q = null;
        if(t.lchild == null)                     //左子树为空 
        {
            q = t.parent;
            if(q==null)
            	root=t.rchild;
            else{
            	if(key<q.value)
            		q.lchild=t.rchild;
            	else
            		q.rchild=t.rchild;
            }
            ts.shorter = TRUE;
        }
        else if(t.rchild == null)                    //右子树为空 
        {
            q = t.parent;
            if(q==null)
            	root=t.lchild;
            else{
            	if(key<q.value)
            		q.lchild=t.lchild;
            	else
            		q.rchild=t.lchild;
            }
            ts.shorter = TRUE;
        }
        else                                            //左右子树都存在,
        {
            q = t.lchild;
            while(q.rchild!=null)
            {
                q = q.rchild;
            }
            t.value = q.value;
            deleteAVL(t.lchild, q.value, ts);   //在左子树中递归删除前驱结点 
        }
    }
    else if(key < t.value)                         //左子树中继续查找 
    {
        if(!deleteAVL(t.lchild, key, ts))
        {
            return FALSE;
        }
        if(ts.shorter)
        {
            switch(t.bf)
            {
            case LH:
                t.bf = EH;
                ts.shorter = TRUE;
                break;
            case EH:
                t.bf = RH;
                ts.shorter = FALSE;
                break;
            case RH:
            	 if(t.rchild.bf == EH)    //注意这里,画图思考一下 
                     ts.shorter = FALSE;
                 else
                     ts.shorter = TRUE;
                RightBalance(t);        //右平衡处理   
                break;
            }
        }
    }
    else                                //右子树中继续查找 
    {
        if(!deleteAVL(t.rchild, key, ts))
        {
            return FALSE;
        }
        if(ts.shorter)
        {
            switch(t.bf)
            {
            case LH:
            	 if(t.lchild.bf == EH)  //注意这里,画图思考一下 
                     ts.shorter = FALSE;
                 else
                     ts.shorter = TRUE;
                LeftBalance(t);         //左平衡处理 
                break;
            case EH:
                t.bf = LH;
                ts.shorter = FALSE;
                break;
            case RH:
                t.bf = EH;
                ts.shorter = TRUE;
                break;
            }
        }
    }
    return TRUE;
}
 
	
	//前序遍历
		private void preOrder(Node r){
			if(r==null)
				return;
			System.out.print(r.value+",");
			preOrder(r.lchild);
			preOrder(r.rchild);
		}
		public void preOrder(){
			preOrder(root);
		}
		//中序遍历
		private void inOrder(Node r){
			if(r==null)
				return;
			inOrder(r.lchild);
			System.out.print(r.value+",");
			inOrder(r.rchild);
		}
		public void inOrder(){
			inOrder(root);
		}
	
	public static void main(String[] args) {
		int[] a={5,3,4,1,2,8,6,7};
		AVLTree tree=new AVLTree();
		for(int i=0;i<a.length;i++){
			tree.insertAVL(a[i]);
		}
		System.out.println("前序遍历:");
		tree.preOrder();
		System.out.println();
		System.out.println("中序遍历:");//二叉排序树中序遍历是递增序列
		tree.inOrder();
		System.out.println();
		tree.deleteAVL(5);
		System.out.println("前序遍历:");
		tree.preOrder();
		System.out.println();
		System.out.println("中序遍历:");//二叉排序树中序遍历是递增序列
		tree.inOrder();
		System.out.println();
		
	}
}

class TS{
	public boolean taller=false;
	public boolean shorter=false;
}

 

点赞