AVL树概念
前面学习二叉查找树和二叉树的各种遍历,但是其查找效率不稳定(斜树),而二叉平衡树的用途更多。查找相比稳定很多。(欢迎关注数据结构专栏)
AVL树是带有平衡条件的二叉查找树。这个平衡条件必须要容易保持。而且要保证它的深度是O(logN).
AVL的条件是左右树的高度差(平衡因子)不大于1;并且它的每个子树也都是平衡二叉树。
对于平衡二叉树的最小个数,n0=0;n1=1;nk=n(k-1)+n(k-2)+1;(求法可以类比斐波那契!)
难点:AVL是一颗二叉排序树,用什么样的规则或者规律让它能够在复杂度不太高的情况下实现动态平衡呢?
不平衡概况
四种平衡旋转方式
◆出现这种情况的原因是节点的右侧的右侧较深这时候不平衡节点需要左旋。再细看过程。
◆再左旋的过程中,root(oldroot)节点下沉,中间节点(newroot)上浮.而其中中间节点(newroot)的右侧依然不变。
◆它上浮左侧所以需要指向根节点(oldroot)(毕竟一棵树)。但是这样newroot原来左侧节点H空缺。而我们需要仍然让整个树完整并且满足二叉排序树的规则。
◆而刚好本来oldroot右侧指向newroot变成oldroot被newroot左侧指向。所以oldroot右侧空缺,刚好这个位置满足在oldroot的右侧。在newroot的左侧。.所以我们将H插入在这个位置。 其中H可能为NULL。不过不影响操作!
function BTNode(left, right, element) {
this.left = left;
this.right = right;
this.element = element;
}
RR平衡旋转(左单旋转)
function RRbanlance(oldroot)
{
let newroot=oldroot.right;
oldroot.right=newroot.left;
newroot.left=oldroot;
return newroot;
}
function LLbanlance(oldroot)
{
let newroot=oldroot.left;
oldroot.left=newroot.right;
newroot.right=oldroot;
return newroot;
}
RL平衡旋转(先右后左双旋转)
◆产生不平衡的条件原因是:
◆root节点右侧左侧节点的深度高些,使得与左侧的差大于1.这个与我们前面看到的左旋右旋不同的是因为它的结构不能直接变一下就可以完成
。
◆因为对于右左结构,中间的最大,两侧的最小。但是下面的比上面大(下面在上面右侧)所以如果平衡的话,那么右左的R.L应该在中间,而R应该在右侧。原来的root在左侧。
◆所以节点的变化浮动比较大,而且需要妥善处理各个子节点的移动使其满足二叉排序树的性质! 期间考虑树高度变化即可!
◆这种双旋转其实也很简单。不要被外表唬住。基于前面的单旋转,双旋转有两种具体逻辑思路。
◆首先根据ROOT,R,R.L三个节点变化。R.L肯定要在最顶层。左右分别指向ROOT和R。那么这其中R.left,ROOT.right发生变化(原来分别是R,L和R)暂时为空。而刚好根据左右大小关系可以补上R.L的左右节点。
◆这样思考整棵树也可以完成平衡,但是要考虑树的高度变化。
function RLbanlance(oldroot)
{
let newroot=oldroot.right.left;
oldroot.right.left=newroot.right;
newroot.right=oldroot.right;
oldroot.right=newroot.left;
newroot.left=oldroot;
return newroot;
}
LR平衡旋转(先左后右单旋转)
function LRbanlance(oldroot)
{
let newroot=oldroot.left.right;
oldroot.left.right=newroot.left;
newroot.left=oldroot.left;
oldroot.left=newroot.right;
newroot.right=oldroot;
return newroot;
}
理论部分转至:https://www.cnblogs.com/bigsai/p/11407395.html 用java实现的,有兴趣的可以去看看,讲的很清晰!