平衡二叉树的java递归实现

平衡二叉树的操作难点在于如何调整平衡,根据情况可以分为LL、RR、LR、RL旋转四种方法,这是java的递归版本,后面打算用非递归实现一下,此博客是根据博客:http://blog.csdn.net/javazejian整理而成,原博客图文并茂,应该是花了不少心思研究,讲得也非常详细,特此整理收藏。

package avltree;

/**
 * 平衡二叉搜索树(AVL树)节点
 */
class AVLNode{

    public AVLNode left;//左结点

    public AVLNode right;//右结点

    public int data;

    public int height;//当前结点的高度

    public AVLNode(int data) {
        this(null,null,data);
    }

    public AVLNode(AVLNode left, AVLNode right, int data) {
        this(left,right,data,0);
    }

    public AVLNode(AVLNode left, AVLNode right, int data, int height) {
        this.left=left;
        this.right=right;
        this.data=data;
        this.height = height;
    }
     

}

//平衡二叉树
public class MyAVLTree {
	
	private AVLNode root;  //根节点
	
	//或取节点的高度
    private int height(AVLNode subtree){
        if (subtree==null){
            return 0;
        }else {
            int l=height(subtree.left);
            int r=height(subtree.right);
            return (l>r) ? (l+1):(r+1);//返回并加上当前层
        }
    }

    /**
     * 左左单旋转(LL旋转) w变为x的根结点, x变为w的右子树
     * @return
     */
    private AVLNode singleRotateLeft(AVLNode x){
        //把w结点旋转为根结点
        AVLNode w=  x.left;
        //同时w的右子树变为x的左子树
        x.left=w.right;
        //x变为w的右子树
        w.right=x;
        //重新计算x/w的高度
        x.height=Math.max(height(x.left),height(x.right))+1;
        w.height=Math.max(height(w.left),x.height)+1;
        return w;//返回新的根结点
    }
    
    /**
     * 右右单旋转(RR旋转) x变为w的根结点, w变为x的左子树
     * @return
     */
    private AVLNode singleRotateRight(AVLNode w){
    	//把w节点的右孩子变成新的根节点
        AVLNode x=w.right;
       //
        w.right=x.left;
        x.left=w;

        //重新计算x/w的高度
        w.height=Math.max(height(w.left),height(w.right))+1;
        x.height=Math.max(height(x.left),w.height)+1;

        //返回新的根结点
        return x;
    }

    /**
     * 左右旋转(LR旋转) x(根) w y 结点 把y变成根结点
     * @return
     */
    private AVLNode doubleRotateWithLeft(AVLNode x){
        //w先进行RR旋转
        x.left=singleRotateRight(x.left);
        //再进行x的LL旋转
        return singleRotateLeft(x);
    }

    /**
     * 右左旋转(RL旋转)
     * @param w
     * @return
     */
    private AVLNode doubleRotateWithRight(AVLNode x){
        //先进行LL旋转
        x.right=singleRotateLeft(x.right);
        //再进行RR旋转
        return singleRotateRight(x);
    }

    /**
    * 插入方法
    * @param data
    */
    public void insert(int data) {
       this.root=insert(data,root);
    }

    private AVLNode insert(int data , AVLNode p){

       //说明已没有孩子结点,可以创建新结点插入了.
       if(p==null){
           p=new AVLNode(data);
       }else if(data<p.data){//向左子树寻找插入位置
           p.left=insert(data,p.left);

           //插入后计算子树的高度,等于2则需要重新恢复平衡,由于是左边插入,左子树的高度肯定大于等于右子树的高度
           if(height(p.left)-height(p.right)==2){
               //判断data是插入点的左孩子还是右孩子
               if(data<p.left.data){
                   //进行LL旋转
                   p=singleRotateLeft(p);
               }else {
                   //进行左右旋转
                   p=doubleRotateWithLeft(p);
               }
           }
       }else if (data>p.data){//向右子树寻找插入位置
           p.right=insert(data,p.right);

           if(height(p.right)-height(p.left)==2){
               if (data<p.right.data){
                   //进行右左旋转
                   p=doubleRotateWithRight(p);
               }else {
                   p=singleRotateRight(p);
               }
           }
       }
       else
        ;//if exist do nothing
       //重新计算各个结点的高度
       p.height = Math.max( height( p.left ), height( p.right ) ) + 1;

       return p;//返回根结点
    }
    
    /**
     * 删除方法
     * @param data
     */
    public void remove(int data) {
        this.root=remove(data,root);
    }

    /**
     * 删除操作
     * @param data
     * @param p
     * @return
     */
    private AVLNode remove(int data,AVLNode p){

        if(p ==null)
            return null;

        //从左子树查找需要删除的元素
        if(data<p.data){
            p.left=remove(data,p.left);

            //检测是否平衡
            if(height(p.right)-height(p.left)==2){
                AVLNode currentNode=p.right;
                //判断需要那种旋转
                if(height(currentNode.left)>height(currentNode.right)){
                    //LL
                    p=singleRotateLeft(p);
                }else{
                    //LR
                    p=doubleRotateWithLeft(p);
                }
            }

        }
        //从右子树查找需要删除的元素
        else if(data>p.data){
            p.right=remove(data,p.right);
            //检测是否平衡
            if(height(p.left)-height(p.right)==2){
                AVLNode currentNode=p.left;
                //判断需要那种旋转
                if(height(currentNode.right)>height(currentNode.left)){
                    //RR
                    p=singleRotateRight(p);
                }else{
                    //RL
                    p=doubleRotateWithRight(p);
                }
            }
        }
        //已找到需要删除的元素,并且要删除的结点拥有两个子节点
        else if(p.right!=null&&p.left!=null){

            //寻找替换结点
            p.data=findMin(p.right).data;

            //移除用于替换的结点
            p.right = remove( p.data, p.right );
        }
        else {
            //只有一个孩子结点或者只是叶子结点的情况
            p=(p.left!=null)? p.left:p.right;
        }

        //更新高度值
        if(p!=null)
            p.height = Math.max( height( p.left ), height( p.right ) ) + 1;
        return p;
    }
    
    /**
    * 查找最小值结点
    * @param p
    * @return
    */
    private AVLNode findMin(AVLNode p){

       if (p==null)//结束条件
           return null;
       else if (p.left==null)//如果没有左结点,那么t就是最小的
           return p;
       return findMin(p.left);
    }

    /**
    * 查找最大值结点
    * @param p
    * @return
    */
//    private AVLNode findMax(AVLNode p){
//       if (p==null)//结束条件
//           return null;
//       else if (p.right==null)
//           return p;
//       return findMax(p.right);
//    }

	//先序遍历
	public void preOrder(AVLNode Root) {
		//如果不是空树
		if(Root!=null) {
			//先访问根节点
			System.out.print(Root.data+" ");
			//递归先序遍历左子树
			preOrder(Root.left);
		    //递归先序遍历右子树
			preOrder(Root.right);
		}
	}
	
	//中序遍历
	public void midOrder(AVLNode Root) {
		//如果不是空树
		if(Root!=null) {
			//递归中序遍历左子树
			midOrder(Root.left);
			//再访问根节点
			System.out.print(Root.data+" ");
		    //递归中序遍历右子树
			midOrder(Root.right);
		}
	}
	
	public static void main(String[] args) {
		MyAVLTree mat=new MyAVLTree();
		//插入完成后是平衡的
		int[] a= {10,8,15,4,9,11,20,3,5};
		for(int i=0;i<a.length;i++) {
			mat.insert(a[i]);
		}
		System.out.print("先序遍历:");
		mat.preOrder(mat.root);
		System.out.println();
		System.out.print("中序遍历:");
		mat.midOrder(mat.root);
		System.out.println();

		//这里只拿出一个测试,其他也可以测试一下
		//在节点8的左子树的左孩子上插入一个2,则会破坏平衡
		mat.insert(2);
		System.out.println("插入节点2后:LL旋转");
		System.out.print("先序遍历:");
		mat.preOrder(mat.root);
		System.out.println();
		System.out.print("中序遍历:");
		mat.midOrder(mat.root);
		System.out.println();
		
		
	}

}

猜你喜欢

转载自blog.csdn.net/qiuxinfa123/article/details/83589979
今日推荐