基础
为什么需要AVL树?
先回顾BST的问题,如果插入数据是有序的,比如1 → 2 → 3 → 4 → 5
BST会退化成:
1
\
2
\
3
\
4
\
5
此时,查找复杂度从O(logN)退化到O(N)。
AVL树的目标:始终保持“平衡”的BST。(也就是说:任意节点的左右子树高度差"平衡因子"<=1)
保持平衡的方法就是“旋转”,当插入/删除后,|平衡因子| > 1,就说明树部平衡了,需要旋转恢复。
四种失衡类型
LL(左左)
30
/
20
/
10
解决方式:右旋
RR(右右)
10
\
20
\
30
解决方式:左旋
LR(左右)
30
/
10
\
20
解决方式:先左旋再右旋
RL(右左)
10
\
30
/
20
解决方式:先右旋再左旋
实现
#include <algorithm> //max
struct TreeNode
{
int val;
int height;
TreeNode* left;
TreeNode* right;
TreeNode(int v) : val(v), height(1), left(nullptr), right(nullptr) {}
};
int getHeight(TreeNode* node)
{
return node ? node->height : 0;
}
int getBalance(TreeNode* node)
{
return node ? getHeight(node->left) - getHeight(node->right) : 0;
}
//左旋
TreeNode* leftRotate(TreeNode* x)
{
//传来的参数是失衡节点
//左旋:将当前节点的右孩子提升为新的根节点,当前节点成为其左子节点,
//同时将右孩子原本的左子树调整为当前节点的右子树
TreeNode* y = x->right;
TreeNode* T2 = y->left;
y->left = x;
x->right = T2;
//更新高度
x->height = std::max(getHeight(x->left), getHeight(x->right));
y->height = std::max(getHeight(y->left), getHeight(y->right));
return y;
}
//右旋
TreeNode* rightRotate(TreeNode* y)
{
TreeNode* x = y->left;
TreeNode* T2 = x->right;
x->right = y;
y->left = T2;
x->height = std::max(getHeight(x->left), getHeight(x->right));
y->height = std::max(getHeight(y->left), getHeight(y->right));
return x;
}
TreeNode* insert(TreeNode* root, int val)
{
//1.BST插入
if(root == nullptr) return new TreeNode(val);
if (val > root->val) root->right = insert(root->right, val);
else if (val < root->val) root->left = insert(root->left, val);
else return root;
//2.更新高度
root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
//3.计算平衡因子
int balance = getBalance(root);
//4.旋转(四种情况)
//LL
if (balance > 1 && val < root->left->val) //当平衡因子大于1,说明左子树过高;如果插入值小于左子节点的值,说明插入发生在左子树的左侧,属于LL型失衡,需要通过一次右旋来恢复平衡
return rightRotate(root);
//RR
if (balance < -1 && val > root->right->val)
return leftRotate(root);
//LR
if (balance > 1 && val > root->left->val)
{
root->left = leftRotate(root->left);
return rightRotate(root);
}
//RL
if (balance < -1 && val < root->right->val)
{
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}