Alt_Shift

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

总结

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

 

posted on 2020-02-06 14:23  Alt_Shift  阅读(140)  评论(0编辑  收藏  举报