平衡二叉查找树(AVL)的插入

来源:互联网 发布:清朗网络 青年力量海报 编辑:程序博客网 时间:2024/05/16 16:14

平衡二叉查找树的概念就不多介绍了,这边主要说明一下如何进行插入操作
在平衡二叉树中插入结点与二叉查找树最大的不同在于要随时保证插入后整棵二叉树是平衡的。那么调整不平衡树的基本方法就是: 旋转 。 下面我们归纳一下平衡旋转的4种情况
1) 绕某元素左旋转 LL(右子树出现右不平衡)
这里写图片描述
分析一下:在插入数据100之前,左图中的 ST树只有80节点的平衡因子是-1(左高-右高),但整棵树还是平衡的。加入100之后,80节点的平衡因子就成为了-2,此时平衡被破坏。需要左旋转成右图。
当树中节点X的右孩子的右孩子上插入新元素,且平衡因子从-1变成-2后,就需要绕节点X进行左旋转。
2) 绕某元素右旋转 RR(左子树出现左不平衡)
这里写图片描述

当树中节点X的左孩子的左孩子上插入新元素,且平衡因子从1变成2后,就需要绕节点X进行右旋转。
3) 绕某元素的左子节点左旋转,接着再绕该元素自己右旋转。 此情况下就是左旋与右旋 的结合,具体操作时可以分解成这两种操作,只是围绕点不一样而已。LR(左子树出现右不平衡)
这里写图片描述

当树中节点X的左孩子的右孩子上插入新元素,且平衡因子从1变成2后,就需要先绕X的左子节点Y左旋转,接着再绕X右旋转
4) 绕某元素的右子节点右旋转,接着再绕该元素自己左旋转。 此情况下就是 右旋与左旋 的结合,具体操作时可以分解 成这两种操作,只是围绕点不一样而已 。RL(右子树左不平衡)
这里写图片描述
当树中节点X的右孩子的左孩子上插入新元素,且平衡因子从-1变成-2后,就需要 先绕X的右子节点Y右旋转,接着再绕X左旋转

附上这几种操作的java版本的代码,代码自己用不同的用例测过,如果有什么地方没有考虑到,欢迎指正^0^

import java.util.ArrayList;import java.util.List;public class AVL {    class TreeNode{        int value;        int bf;        TreeNode left,right;        TreeNode(int v){            value = v;            bf = 0;        }    }    public TreeNode buildTree(int[] nums){        if(nums.length == 0) return null;        TreeNode PRoot = new TreeNode(0);        TreeNode root = new TreeNode(nums[0]);        //为了能让后面可以改变root的地址而设        PRoot.left = root;        for(int i = 1; i < nums.length ; i++){            insertTree(nums[i],PRoot);        }        return root;    }    public void insertTree(int num,TreeNode PRroot){        if(PRroot.left == null)             return;        TreeNode A=PRroot.left , B=PRroot.left ;        TreeNode insertNode = new TreeNode(num);         TreeNode temp = PRroot.left ;        TreeNode AFather = null,tempFather = null;        while(temp != null){            //找到从下到上最近的可能出现不平衡的节点            if(temp.bf != 0){                A = temp;                AFather = tempFather;            }            tempFather = temp;            if(num < temp.value)                temp = temp.left;            else                temp = temp.right;        }        //插入孩子        if(num > tempFather.value)            tempFather.right = insertNode;        else            tempFather.left = insertNode;        adjustBalance(A,AFather,insertNode,PRroot);//      printTree(PRroot);    }    public TreeNode updateBF(TreeNode insert,TreeNode node){        if(insert.value < node.value){            node.bf +=1;            return node.left;        }        else {            node.bf -= 1;            return node.right;        }    }    public void adjustBalance(TreeNode A,TreeNode AFather,TreeNode insert,TreeNode PRoot){        //确定B节点,修改A的bf        TreeNode B = updateBF(insert,A);;        //B不是插入点则也需要更新B的bf        System.out.println("B.value= " + B.value);        //在原来都平衡的一边加上一个值,A就会是root,所以要修改从B到插入节点之间的bf值        TreeNode temp = B;        while(temp.value != insert.value){            updateBF(insert,temp);            if(insert.value < temp.value)                temp = temp.left;            else                 temp = temp.right;        }        //LL        if(A.bf == 2 && B.bf == 1){            A.left = B.right;            B.right = A;            A.bf = 0;            B.bf = 0;            updateChild(AFather,A,B,PRoot);        }        //RR        else if(A.bf == -2 && B.bf == -1){            A.right = B.left;            B.left = A;            A.bf = 0;            B.bf = 0;            updateChild(AFather,A,B,PRoot);        }        //LR        else if(A.bf == 2 && B.bf == -1){            TreeNode C = B.right;            //先往左转成LL            B.right = C.left;            C.left = B;            //LL            A.left = C.right;            C.right = A;            //插入的点如果比C大最后会落在A的左边,比C小会落在B的右边            //A的右边 和B的左边一定有元素            if(insert.value > C.value){                A.bf = 0;                B.bf = -1;                C.bf = 0;            }            else if(insert.value < C.value) {                A.bf = 1;                B.bf = 0;                C.bf = 0;               }            //插入点就是C的话            else{                A.bf = 0;                B.bf = 0;            }            updateChild(AFather,A,C,PRoot);        }        //RL        else if(A.bf == -2 && B.bf == 1){            TreeNode C = B.left;            //先转成RR            B.left = C.right;            C.right = B;            //RR            A.right= C.left;            C.left = A;            //插入的点如果比C大最后会落在B的左边,比C小会落在A的右边            //因为B右边和A的左边一定会有元素            if(insert.value > C.value){                B.bf = 0;                A.bf = 1;                C.bf = 0;            }            else if(insert.value < C.value){                A.bf = 0;                B.bf = -1;                C.bf = 0;            }            //C就是要插入的元素            else{                A.bf = 0;                B.bf = 0;            }            updateChild(AFather,A,C,PRoot);        }    }    public void updateChild(TreeNode father,TreeNode originChild,TreeNode newChild,TreeNode PRoot){        if(father == null)            PRoot.left = newChild;        else if(originChild == father.left)            father.left = newChild;        else            father.right = newChild;    }    public void printTree(TreeNode tree){        if(tree.left == null) return;        List<TreeNode> nodes = new ArrayList<TreeNode>();        nodes.add(tree.left);        printNode(nodes,"value");        System.out.println("***************");        printNode(nodes,"bf");        System.out.println("#################");    }    public void printNode(List<TreeNode> nodes,String type){        if(nodes.size() == 0) return;        List<TreeNode> childs = new ArrayList<TreeNode>();        for(TreeNode node:nodes){            if(type.equals("value"))                System.out.print(node.value + " ");            else                System.out.print(node.bf + " ");            if(node.left != null)                childs.add(node.left);            if(node.right != null)                childs.add(node.right);        }        System.out.println();        printNode(childs,type);    }    public static void main(String[] args){        int[] nums={10,20,29,24,12,53,45,90,100,290,28};        AVL avl = new AVL();        TreeNode tree = avl.buildTree(nums);        avl.printTree(tree);    }}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 丈夫的前儿子偷了我的钱我该怎么办 从日本寄的邮包被海关扣下了怎么办 卖家要求退货寄过去的货坏了怎么办 寄快递发货单丢了货发出去了怎么办 酷派手机电源键坏了开不了机怎么办 红米4a进水后开机就黑屏了怎么办 红米1s进水后开机了黑屏了怎么办 魅族手机已锁定魅族账号忘了怎么办 魅族5糸统升级后开不了机了怎么办 如果别人用电脑登了你的微信怎么办 消逝的光芒买错了买的普通版怎么办 在人人车卖了个车买家不过户怎么办 应用锁密码和密保问题都忘了怎么办 不小心在微信公众号发了消息怎么办 微信漂流瓶不能用了被投诉了怎么办 货物少了拉货的不承认少了怎么办 寄的快递号码留错了已经寄走怎么办 网购快递放在单位门卫室丢了怎么办 顺丰生鲜速配时效内食物坏了怎么办 竟尤理财跑路怎么办钱追的回来吗 博贝游戏用支付宝提不了现该怎么办 陌陌钱包没绑支付宝就体现了怎么办 鞋子让太阳晒的一只大一只小怎么办 美团不让上饿了么平台们商家怎么办 在汇通信诚租贷款买车被骗后怎么办 我的网银账户里的钱被盗了怎么办 老赖跑到国外去了还换了国籍怎么办 内裤把屁股两边磨得又肿又疼怎么办 京东在面临供货商不供货时怎么办的 打错的消息想撤回但按了删除怎么办 顺丰快递寄的黄皮和荔枝坏了怎么办 我发快递写错地址备签收不还怎么办 新买的床上四件套用着全身痒怎么办 华为畅玩6x锁屏密码忘了怎么办 我在淘宝上买了货不发货咋怎么办 在快递公司寄的东西丢了我该怎么办 不小心给了快递员子一个差评怎么办 不小心用发霉了的杯子喝了水怎么办 唐三复活了小舞失去的魂环怎么办了 我该怎么办?身陷动漫城输了很多钱 庄家开2球大小球踢成2球怎么办