这个树,怎么一下就平衡了?(三)

joytrian
发布于 2022-7-6 17:06
浏览
0收藏

 

代码实现
首先对于节点多个height属性。用于计算高度(平衡因子)

插入是递归插入,递归是一个来回的过程,去的过程进行插入,回的过程进行高度更新,和检查是否平衡。推荐不要写全局递归计算高度,效率太低下,事实上高度变化只和插入和平衡有关,仔细考虑即不会有疏漏!

代码写的比较早,如有命名不规范的情况,还请勿喷,如果有疏漏还请指出!

import java.util.ArrayDeque;
import java.util.Queue;

public class AVLTree {

    class node
    {
        int value;
        node left;
        node right;
        int height;
        public node() {

        }
        public node(int value)
        {
            this.value=value;
            this.height=0;
        }
        public node(int value,node left,node right)
        {
            this.value=value;
            this.left=left;this.right=right;
            this.height=0;
        }
    }
    node root;// 根

    public AVLTree() {
        this.root = null;
    }

    public boolean isContains(int x)// 是否存在
    {
        node current = root;
        if (root == null) {
            return false;
        }
        while (current.value != x && current != null) {
            if (x < current.value) {
                current = current.left;
            }
            if (x > current.value) {
                current = current.right;
            }
            if (current == null) {
                return false;
            } // 在里面判断如果超直接返回
        }
        // 如果在这个位置判断是否为空会导致current.value不存在报错
        if (current.value == x) {
            return true;
        }
        return false;
    }

    public int getHeight(node t)
    {
        if(t==null) {return -1;}//
        return t.height;
        //return 1+Math.max(getHeight(t.left), getHeight(t.right));这种效率太低
    }
    public void cengxu(node t) {//层序遍历
        Queue<node> q1 = new ArrayDeque<node>();
        if (t == null)
            return;
        if (t != null) {
            q1.add(t);
        }
        while (!q1.isEmpty()) {
            node t1 = q1.poll();
            if (t1.left != null)
                q1.add(t1.left);
            if (t1.right != null)
                q1.add(t1.right);
            System.out.print(t1.value + " ");
        }
        System.out.println();
    }
    public void zhongxu(node t)//中序遍历 中序遍历:左子树---> 根结点 ---> 右子树
    {//为了测试改成中后都行
        if(t!=null)
        {
            zhongxu(t.left);
            System.out.print(t.value+" ");//访问完左节点访问当前节点
            zhongxu(t.right);
            //System.out.print(t.value+" ");//访问完左节点访问当前节点
        }
    }
    public void qianxu(node t)//前序递归 前序遍历:根结点 ---> 左子树 ---> 右子树
    {
        if(t!=null) {
            System.out.print(t.value+" ");//当前节点
            qianxu(t.left );
            qianxu(t.right);}
    }
    public void insert(int value) {
        root=insert(value, root);
    }
    public node insert(int x,node t)//插入   t是root的引用
    {
        node a1=new node(x);
        //if(root==null) {root=a1;return root;}        
        if(t==null)    {return a1;}
        //插入操作。递归实现
        else if(t!=null)
        {
            if(x<t.value)
            { t.left=insert(x,t.left);}
            else
            { t.right= insert(x,t.right);}
        }
        /*
         * 更新当前节点的高度,因为整个插入只有被插入的一方有影响,
         * 所以递归会更新好最底层的,上层可直接调用
         */
        t.height=Math.max(getHeight(t.left),getHeight(t.right))+1;//不要写成递归, 递归效率低
        return banlance(t);//因为java对象传参机制,需要克隆,不可直接t=xx 否则变换      
    }

    private node banlance(node t) {
        // TODO Auto-generated method stub
        //if(t==null)return null;
        int lefthigh=getHeight(t.left);
        int righthigh=getHeight(t.right);
        if(Math.abs(lefthigh-righthigh)<=1)//不需要平衡滴
        {    return t;}
        else if(lefthigh<righthigh)//右侧大
        {
            if(getHeight(t.right.left)<getHeight(t.right.right))//RR需要左旋
            {
                return  getRRbanlance(t);
            }
            else {
                return getRLbanlance(t);
            }
        }
        else {
            if(getHeight(t.left.left)>getHeight(t.left.right))//ll 左左
            {
                return getLLbanlance(t);
            }
            else {
                return getLRbanlance(t);
            }
        }
    }
    /*
     *        oldroot(平衡因子为2,不平衡)    ==>   newroot
     *       /    \                              /    \
     *      B     newroot(平衡因子为1)        oldroot   D
     *             /    \                      / \      \
     *            C      D                    B   C      E
     *                    \
     *                     E
     */

    private node getRRbanlance(node oldroot) {//右右深,需要左旋
        // TODO Auto-generated method stub
        node newroot=oldroot.right;
        oldroot.right=newroot.left;
        newroot.left=oldroot;
        oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
        newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新计算
        return newroot;
    }
    /*
     * 右旋同理
     */
    private node getLLbanlance(node oldroot) {//LL小,需要右旋转
        // TODO Auto-generated method stub
        node newroot=oldroot.left;
        oldroot.left=newroot.right;
        newroot.right=oldroot;
        oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
        newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新金酸    
        return newroot;
    }

    private node getLRbanlance(node oldroot) {
        oldroot.left =getRRbanlance(oldroot.left);
        oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1;
        return getLLbanlance(oldroot);

    }

    /*          (不平衡出现在右左节点)
     *         oldroot       ==>          newroot
     *        /        \                 /       \
     *       A          B             oldroot     B
     *                /   \           /    \     /  \
     *           newroot   D         A      E    F   D
     *            /   \
     *           E     F
     */

    private node getRLbanlance(node oldroot) {//右左深    
//        node newroot=oldroot.right.left;
//        oldroot.right.left=newroot.right;
//        newroot.right=oldroot.right;
//        oldroot.right=newroot.left; 
//        newroot.left=oldroot;
//        oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
//        newroot.right.height=Math.max(getHeight(newroot.right.left),getHeight(newroot.right.right))+1;
//        newroot.height=Math.max(getHeight(oldroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新金酸  
        oldroot.right =getLLbanlance(oldroot.right);
        oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1;
        return getRRbanlance(oldroot);

    }
}

 

测试情况:

这个树,怎么一下就平衡了?(三)-鸿蒙开发者社区

AVL的理解需要时间,当然笔者的AVL自己写的可能有些疏漏,如果有问题还请各位一起探讨!

当然,除了插入,AVL还有删除等其他操作,(原理相似。删除后平衡)有兴趣可以一起研究。

结语
原创不易,如果本文对你有帮助,还请动动小手,帮忙点个赞和在看,分享给好友或者朋友圈,谢谢啦!

 

文章转自公众号:bigsai

标签
已于2022-7-6 17:06:01修改
收藏
回复
举报
回复
    相关推荐