• AVL树


    AVL树全程二叉平衡树,是在二叉查找树之上添加一个平衡条件,那就是左右子树的高度差不超过2,二叉查找树的优点就是插入和查询一个节点的速度快,但是当二叉查找树出现偏缀也就是每个节点都只有左孩子,这个树就会无限向下延申导致查找和插入的效率下降,所以二叉平衡树就出现了。

    在这个平衡条件下,就出现了维持二叉树平衡的手段,也就是旋转,在我了解一点这个AVL树的时候我以为这个旋转会很复杂,事实告诉我任何东西只有你上手做你才会了解到他到底难不难。

    首先是二叉平衡树的节点

     1 public class TreeNode {
     2      int val;
     3      TreeNode left;
     4      TreeNode right;
     5      int hight;
     6      public TreeNode(int val, TreeNode left, TreeNode right){
     7          this.val = val;
     8          this.left = left;
     9          this.right = right;
    10          this.hight = 0;
    11      }
    12 }

    节点有一个hight属性,也就是左子树或者右子树的最大值。接下来是增删改查四个方法。

    在增加之前了解四个旋转方法:LL单旋转,RR单旋转,LR双旋转,RL双旋转

     1 public TreeNode leftleftRotation(TreeNode k2){
     2         TreeNode k1 ;
     3         k1 = k2.left;
     4         k2.left = k1.right;
     5         k1.right =  k2;
     6 
     7         k2.hight = max(getHight(k2.right), getHight(k2.left));
     8         k1.hight = max(getHight(k1.left), k2.hight);
     9 
    10         return k1;
    11     }
    LL单旋转
     1 //RR型单旋转
     2     public TreeNode rightRightRotation(TreeNode k2){
     3         TreeNode k1;
     4         k1 = k2.right;
     5         k2.right = k1.left;
     6         k1.right = k2;
     7 
     8         k2.hight = max(getHight(k2.left), getHight(k2.right));
     9         k1.hight = max(getHight(k1.right), k1.hight);
    10 
    11         return k1;
    12     }
    RR单旋转
    //LR双旋转
        public TreeNode leftRightRotation(TreeNode k3){
            k3.left = rightRightRotation(k3.left);
            return leftleftRotation(k3);
        }
    LR双旋转
    1 //RL双旋转
    2     public TreeNode rightLeftRotation(TreeNode k3){
    3         k3.right = leftleftRotation(k3.right);
    4         return rightRightRotation(k3);
    5     }
    RL双旋转

    然后是insert方法,我是用递归写的insert,在每次insert之后判断node是否失衡,如果失衡在判断失衡类型采用哪种旋转方法,增加之后更新高度。

     1 //增加
     2     public void insert(TreeNode node,int val){
     3         if(node == null){
     4             node = new TreeNode(val, null, null);
     5         }
     6         int com = compareTo(val, node.val);
     7 
     8         if(com < 0){
     9             insert(node.left, val);
    10             if(getHight(node.left) - getHight(node.right) == 2){
    11                 if(val < node.left.val){
    12                     node = leftleftRotation(node);
    13                 }else{
    14                     node = leftRightRotation(node);
    15                 }
    16             }
    17         }else if(com > 0){
    18             insert(node.right, val);
    19             if(getHight(node.left) - getHight(node.right) == 2){
    20                 if(val > node.right.val){
    21                     node = rightRightRotation(node);
    22                 }else{
    23                     node = rightLeftRotation(node);
    24                 }
    25             }
    26         }else if(com == 0){
    27             return ;
    28         }
    29         node.hight = max(getHight(node.left), getHight(node.right));
    30     }
    insert

    接着是删除功能,删除节点之后需要寻找替换节点,这个就是跟二叉查找树一样寻找删除节点的前驱节点或者后继节点,在这之前写一个获取最大节点和获取最小节点两个方法。

     1  //获取二叉树的最大节点
     2     public TreeNode getMax(TreeNode root){
     3         TreeNode p,x;
     4         if(root == null){
     5             return root;
     6         }
     7         p = root;
     8         x = p.right;
     9         while(true){
    10             if(x != null){
    11                 p = x;
    12                 x = x.right;
    13             }else{
    14                 return p;
    15             }
    16         }
    17     }
    获取最大节点
     1 //获取二叉树的最小节点
     2     public TreeNode getMin(TreeNode root){
     3         TreeNode p,x;
     4         if(root == null){
     5             return root;
     6         }
     7         p = root;
     8         x = p.left;
     9         while(true){
    10             if(x != null){
    11                 p = x;
    12                 x = x.left;
    13             }else{
    14                 return p;
    15             }
    16         }
    17     }
    获取最小节点
     1 public TreeNode del(TreeNode root, int val){
     2         if(val < root.val){
     3             root.left = del(root.left, val);
     4             if(getHight(root.right) - getHight(root.left) == 2){
     5                 TreeNode node = root.right;
     6                 if(getHight(node.left) > getHight(node.right)){
     7                     root.right = rightLeftRotation(node);
     8                 }else{
     9                     root.right = rightRightRotation(node);
    10                 }
    11             }
    12         }else if(val > root.val){
    13             root.right = del(root.right, val);
    14             if(getHight(root.left) - getHight(root.right) == 2){
    15                 TreeNode node = root.left;
    16                 if(getHight(node.right) > getHight(node.left)){
    17                     root.left = leftRightRotation(node);
    18                 }else{
    19                     root.left = leftleftRotation(node);
    20                 }
    21             }
    22         }else{
    23             //找到删除节点后,如果左子树hight > 右子树hight,用左子树的最大节点替换在删除这个节点。
    24             //左右子树都非空
    25             if ((root.left!=null) && (root.right!=null)) {
    26                 if (getHight(root.left) > getHight(root.right)) {
    27                     TreeNode leftMax = getMax(root.left);
    28                     root.val = leftMax.val;
    29                     del(root.left, leftMax.val);
    30                 } else if (getHight(root.left) < getHight(root.right)) {
    31                     TreeNode rightMin = getMin(root.right);
    32                     root.val = rightMin.val;
    33                     del(root.right, rightMin.val);
    34                 }
    35             }else{
    36                 root = null;
    37             }
    38         }
    39         return root;
    40     }
    del

    最后是查询功能

     1 //查询
     2     public TreeNode sel(TreeNode root, int val){
     3         if(root == null || root.val == val){
     4             return root;
     5         }
     6         if(val < root.val){
     7             root = sel(root.left, val);
     8         }else{
     9             root = sel(root.right, val);
    10         }
    11         return root;
    12     }
    search

    总结

    实现的很简陋,但是帮我理解了这个二叉平衡树的大部分原理,在我以前看来很艰难很复杂的旋转也并不难,只要加油都会有收获的。

  • 相关阅读:
    菜菜小问题——python中print函数 以及单引号、双引号、三引号
    fiddler软件测试——Fiddler抓取https设置详解(图文)
    【转】fiddler抓包时出现了tunnel to ......443 解密HTTPS数据
    小菜菜mysql练习解读分析2——查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )
    c语言基础——基本数据类型
    linux 02
    C#中海量数据的批量插入和更新
    linux 基本命令-01
    Linux -01 安装centos
    mysql 锁和隔离事务
  • 原文地址:https://www.cnblogs.com/frank9571/p/12268584.html
Copyright © 2020-2023  润新知