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

joytrian
发布于 2022-7-6 17:06
6297浏览
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);

    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.

 

测试情况:

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

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

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

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

 

文章转自公众号:bigsai

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


回复
    相关推荐