目录
一、AVL 树的概念
二叉搜索树查找算法的性能取决于二叉树搜索树的形状,而二叉搜索树的形状则取决于数据集。如果数据呈有序排列,则二叉搜索树为单支树,查找的时间复杂度为 O(n);反之,如果二叉搜索树的形状合理,则查找速度较快,查找的时间复杂度为 O()。事实上,树的高度越小,查找速度越快,因此,希望二叉树的高度尽可能小。下面将讨论一种特殊类型的二叉搜索树,称为平衡二叉树(Balanced Binary Tree 或 Height-Balanced Tree),因由前苏联数学家
Adelson-Velskii 和 Landis 提出,所以又称 AVL 树。
平衡二叉树或者是空树,或者是具有如下特征的二叉搜索树:
-
左子树和右子树的高度之差的绝对值不超过 1。
-
左子树和右子树也是平衡二叉树。
若将二叉树上节点的平衡因子(BF, Balance Factor)定义为该节点左子树和右子树的高度之差,则平衡二叉树上的所有节点的平衡因子只可能是 -1、0 和 1。只要二叉树上有一个节点的平衡因子的绝对值大于 1,则该二叉树就是不平衡。
例如,下面图 (a) 所示为两棵平衡二叉树,图 (b) 所示则为两棵不平衡的二叉树,节点中的值为该结点的平衡因子。

因为 AVL 树上任何节点的左右子树的高度之差都不超过 1,则可以证明它的深度和 是同数量级的(其中 n 为节点个数)。由此,其查找的时间复杂度是 O(
)。
二、AVL 树节点的定义
template<class K, class V>
struct AVLNode
{
AVLNode<K, V>* _left;
AVLNode<K, V>* _right;
AVLNode<K, V>* _parent;
std::pair<K, V> _kv;
int _bf;
AVLNode(const std::pair<K, V>& kv = std::pair<K, V>())
: _left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0)
{ }
};
三、AVL 树的插入
当新增的节点 *cur(指向节点的指针为 cur) 插入到其双亲节点 *parent(指向节点的指针为 parent)的左边时,双亲节点的平衡因子 +1;反之,当新增的节点插入到其双亲节点的右边时,双亲节点的平衡因子 -1。
-
若双亲节点的平衡因子原来为 -1 或者 1,在它的左边或者右边插入新增的节点后,它的平衡因子变为 0。由于以
*parent为根节点的子树的高度没有发生变化,因此也不会影响除*parent以外的其它祖先节点的平衡因子,插入完成。
-
若双亲节点的平衡因子原来为 0,在它的左边或者右边插入新增的节点后,它的平衡因子变为 1 或者 -1。由于以
*parent为根节点的子树的高度增高了 1,此时也就会影响其它祖先节点的平衡因子,需要往上更新。
往上更新其它祖先节点的平衡因子的方式和一开始插入新增节点
*cur时更新其双亲节点*parent的平衡因子的方式是一样的,即如果*cur在祖先节点的左子树中,则祖先节点的平衡因子 +1;如果*cur在祖先节点的右子树中,则祖先节点的平衡因子 -1。-
如果祖先节点的平衡因子被更新为 0,则说明更新完成了,也意味着插入完成了。
-
如果祖先节点的平衡因子被更新为 1 或者 -1,则说明还需要继续往上更新,直到某个祖先节点的平衡因子被更新为 0,或者直到更新完根节点,当根节点的平衡因子被更新为 0、1 或者 -1 时,意味着更新和插入也都完成了。
-
如果祖先节点的平衡因子被更新为 2 或者 -2(即其较高的子树增高了),就需要对以该节点为根节点的子树(称为最小不平衡子树)做平衡调整来恢复平衡。
-
四、AVL 树的平衡调整
假设最小不平衡子树的根节点为 A,则失去平衡后进行调整的规律可归纳为下列 4 种情况。
-
LL 型:由于在 A 左子树根节点的左子树上插入节点,A 的平衡因子由 1 增至 2,致使以 A 为根节点的子树失去平衡,则需进行一次向右的顺时针旋转操作。

void LL(Node* pA) { Node* pB = pA->_left; Node* pBR = pB->_right; pA->_left = pBR; if (pBR) pBR->_parent = pA; pB->_right = pA; Node* tmp = pA->_parent; pA->_parent = pB; pB->_parent = tmp; if (tmp == nullptr) // 或者 _root == pA { _root = pB; } else { if (tmp->_left == pA) tmp->_left = pB; else tmp->_right = pB; } pA->_bf = pB->_bf = 0; } -
RR 型:由于在 A 的右子树根节点的右子树上插入节点,A 的平衡因子由 -1 变成 -2,致使以 A 为根节点的子树失去平衡,则需进行一次向左的逆时针旋转操作。

void RR(Node* pA) { No

1万+

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



