AVL树的概念
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。

因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
一棵AVL树或者是空树:
1.它的左右子树都是AVL树
2.左右子树的高度差绝对值不超多 1(-1 / 0 / 1)(简称平衡因子 = 右子树的高度 - 左子树的高度)

增删查改:高度次 -> O(logN)
满二叉树: 2^h - 1 = N
AVL树 : 2^h - x = N
X范围: [1 , 2^(h-1)-1]
AVL树节点的定义和AVL树的插入
AVL == 高度平衡的二叉搜索树
平衡不是相等,而是高度差不超过1;


1.新增在左,parent平衡因子减减
2.新增在右,parent平衡因子加加

3.更新后parent平衡因子 == 0,说明parent所在的子树高度不变,不会影响祖先节点,不用再继续沿着root的路径向上跟新.
4.更新后parent平衡因子 == 1 or -1,说明parent的所在子树的高度发生变化,会影响祖先,需要继续沿着到root节点的路径向上更新。

5.更新后parent平衡因子 == 2 or -2, 说明parent所在的子树高度变化且不平衡,需要对parent所在子树进行旋转,让他平衡。
AVL树的旋转
如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:
旋转的时候需要注意的问题:
1.保持他是搜索树
2.变成平衡树且降低这个子树的高度
3.旋转后更新平衡因子
左单旋

核心操作:
parent -> right = cur-> left
cur -> left = parent

右单旋

核心操作:
parent -> left = cur -> right
cur->right = parent

左右双旋和右左双旋
左右双旋
新节点插入较高左子树的右侧:先左单旋再右单旋

核心操作:
左单旋
cur -> right = curright->left
curright->left = cur
curright->parent = cur->parent
cur->parent = curright
右单旋
parent->left = curright->right
curright->right = parent;
currigjt->parent = parent->parent
parent->parent = curright

因为双旋的原因,平衡因子会因为插入位置的不同发生不同变化:
如果新插入节点在较高左子树的右侧,则记录cur->right的平衡因子
插入在较高右子树的左侧,则记录cur->left的平衡因子
如:
int bf = curright->_bf;
如果bf0,则cur和curright和parent都为0;
如果bf1,则cur->bf = -1, curright和parent的bf为0;
如果bf==-1,则cur和curright的bf为0,parent->bf = 1;
if (bf == 0)
{
cur->_bf = 0;
curright->_bf = 0;
Parent->_bf = 0;
}
else if (bf == -1)
{
cur->_bf = 0;
curright->_bf = 0;
Parent->_bf = 1;
}
else if (bf == 1)
{
cur->_bf = -1;
curright->_bf = 0;
Parent->_bf = 0;
}
else
{
assert(false);
}
而右左双旋则是跟左右双旋差不多只是顺序不同,就不做过多追述了;
AVL树的删除
因为AVL树也是二叉搜索树,可按照二叉搜索树的方式将节点删除,然后再更新平衡因子,只不错与删除不同的时,删除节点后的平衡因子更新,最差情况下一直要调整到根节点的位置。

如果平衡因子更新为0,则需要一直向上更新

如果平衡因子更新为-2/2,则需要根据情况旋转

当parent平衡因子为1/-1则不需要继续向上更新
AVL树的性能
AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 l o g 2 ( N ) log_2 (N) log2(N)。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。
966

被折叠的 条评论
为什么被折叠?



