AVL tree (balanced binary tree) Detailed and Implementation

AVL tree concept

Learning in front of a binary search tree and a variety of binary tree traversal , but its search efficiency unstable (oblique tree), but use more balanced binary tree. Find compared to the much more stable. ( Welcome attention to the data structure column )

  • AVL tree is a binary search tree with Equilibrium Conditions . This condition must be balanced 容易保持. And to ensure that its depth is O (logN).
  • With the proviso that the AVL tree height difference of about ( 平衡因子) is not greater than 1; and each of its sub-tree are also balanced binary tree.
  • For the minimum number of balanced binary tree, n0=0; n1=1; nk=n(k-1)+n(k-2)+1; (Bi Feibo class seeking process may Fibonacci!)

Difficulty: AVL tree is a binary sort, what kind of rules or laws to make it capable of complexity is not too high in the case of dynamically balanced it?
Here Insert Picture Description

Unbalanced Overview

Here Insert Picture Description
If you simply look at a single node, roughly above 四种circumstances, and their final result is there something similar. Just: up and down to change. This still left on the left, the right change at the right side also .
Here Insert Picture Description
This is only for the bottom, to balance that may arise should first figure out:
Here Insert Picture Description
so for the four unbalanced, may appear at the bottom, it may appear in the head, may also appear in an intermediate node, resulting in an imbalance. And we only need to study their first point of imbalance, the whole tree that is balanced after resolving to continue . Of course, in practical solutions will certainly bring 递归ideas to solve the problem.

# 四种平衡旋转方式

RR平衡旋转(左单旋转)

Here Insert Picture Description
出现这种情况的原因是节点的右侧的右侧较深这时候不平衡节点需要左旋。再细看过程。

  • 再左旋的过程中,root(oldroot)节点下沉,中间节点(newroot)上浮.而其中中间节点(newroot)的右侧依然不变。
  • 它上浮左侧所以需要指向根节点(oldroot)(毕竟一棵树)。但是这样newroot原来左侧节点H空缺。而我们需要仍然让整个树完整并且满足二叉排序树的规则
  • 而刚好本来oldroot右侧指向newroot变成oldroot被newroot左侧指向。所以oldroot右侧空缺,刚好这个位置满足在oldroot的右侧。在newroot的左侧。.所以我们将H插入在这个位置。
  • 其中H可能为NULL。不过不影响操作!
    Here Insert Picture Description
    而左旋的代码可以表示为:
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;     
}

LL平衡旋转(右单旋转)

而右旋和左旋相反,但是思路相同,根据上述进行替换即可!
Here Insert Picture Description
代码:

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; 
}

RL平衡旋转(先右后左双旋转)

产生不平衡的条件原因是:

  • root节点右侧左侧节点的深度高些,使得与左侧的差大于1.这个与我们前面看到的左旋右旋不同的是因为它的结构不能直接变一下就可以完成。
  • 因为对于右左结构,中间的最大,两侧的最小。但是下面的比上面大(下面在上面右侧)所以如果平衡的话,那么右左的R.L应该在中间,而R应该在右侧。原来的root在左侧。
  • 所以节点的变化浮动比较大,而且需要妥善处理各个子节点的移动使其满足二叉排序树的性质!
  • 期间考虑树高度变化即可!

这种双旋转其实也很简单。不要被外表唬住。基于前面的单旋转,双旋转有两种具体逻辑思路
思路1:两次旋转RR,LL
Here Insert Picture Description
根据上图所圈的,先对底部使得底部的大小关系变化,使其在满足二叉平衡树的条件下还满足RR结构的二叉树。所以只需要对右节点R先进行右旋,再对ROOT进行左旋即可。
思路2:直接分析
根据初始和结果的状态,然后分析各个节点变化顺序。手动操作这些节点即可!

  • 首先根据ROOT,R,R.L三个节点变化。R.L肯定要在最顶层。左右分别指向ROOT和R。那么这其中R.left,ROOT.right发生变化(原来分别是R,L和R)暂时为空。而刚好根据左右大小关系可以补上R.L的左右节点
  • 这样思考整棵树也可以完成平衡,但是要考虑树的高度变化
    Here Insert Picture Description
    代码为:(注释部分为方案1)
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);
        
    }

LR平衡旋转(先左后右单旋转)

根据上述RL修改即可
Here Insert Picture Description

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

java代码实现

  • 首先对于节点多个height属性。用于计算高度(平衡因子)
  • 插入是递归插入。递归一个来回的过程,去的过程进行插入。回的过程进行高度更新。和检查是否平衡。不要写全局递归计算高度,效率太低下。事实上高度变化只和插入和平衡有关,仔细考虑即不会有疏漏!
    Here Insert Picture Description
    Here Insert Picture Description
    Here Insert Picture Description

    总结

    测试情况:
    Here Insert Picture Description
  • AVL understanding takes time, of course, the author of the AVL to write their own 可能有些疏漏, if there is a problem also please 一起探讨!
  • Of course, in addition to insert, AVL as well as 删除other operations, (the principle is similar. After you remove the balance) are interested can study together.
  • If you need the source code also requested the public attention the author Number: No public view Feature Articles!
  • If 后端、爬虫、数据结构算法other sensory welcome attention to my personal interest in sex public exchange number: bigsai(reply data structure, reptiles, java and other information have a well-prepared!)

Guess you like

Origin www.cnblogs.com/bigsai/p/11407395.html