参考:胡凡,曾磊《算法笔记》
引子
使用有序序列构建BST会形成链式的二叉树,此时查找的复杂度会达到O(n),达不到查询优化的效果。因此需要调整树的结构,使得树的高度在每次插入后仍保持O(log n)级别,使查询操作仍保持O(log n)复杂度。
概念
AVL tree是一棵平衡的二叉查找树。
- x结点的平衡因子:x结点左、右子树高度之差。为此要在struct Node中加入height字段,记录以结点x为根结点的子树高度。
- height:空结点height为0,叶子结点height为1。以结点x为根的子树的height为max(x的左子树高度, x的右子树高度)+ 1
AVL tree要求任意结点平衡因子绝对值不超过1。
AVL tree的基本操作
*以下操作前提是各结点value均不同。
查找void search(Node* root, int value)
做法同BST的查找。
复杂度O(log n)
插入void insert(Node* &root, int value)
插入新结点可能会使从根结点到插入结点的路径上的结点的平衡因子绝对值大于1。
只要把最靠近插入结点的失衡结点调整到正常,路径上所有结点就都会平衡。
⚠️传Node*
的引用
⚠️插入后注意更新结点高度
⚠️调整操作中注意更新结点高度
步骤
- 先插入,插入后紧跟着更新子树高度(自顶而下递归的插入,自下而上递归的更新树高)
- 根据平衡因子判断树形,作相应调整。
调整用到的操作 ⚠️传引用
左旋
void L(Node* &root)
右旋
void R(Node* &root)
左旋、右旋互为逆操作。
需调整的树形可分为
LL、RR(一次旋转)
LL需右旋,RR需左旋
LR、RL(两次旋转)
LR需左旋左子树(变成LL),再右旋
RL需右旋右子树(变成RR),再左旋
- 插入到x结点左子树,若x结点失衡,只可能形成以x结点为根的LL、LR形
- 插入到x结点右子树,若x结点失衡,只可能形成以x结点为根的RR、RL形
AVL tree的建立
依次insert结点即可。
Node* createAVL(int data[], int nn)
删除
暂时跳过🤮
例
#include <cstdio>
#include <algorithm>
using namespace std;
struct Node {
int value, height;
Node *lchild, *rchild;
};
int getHeight(Node *root) {
return root == NULL ? 0 : root->height;
}
void updateHeight(Node *root) {
root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;
}
int getBalanceFactor(Node *root) {
return getHeight(root->lchild) - getHeight(root->rchild);
}
void LeftRotation(Node *&root) {
Node *temp = root->rchild;
root->rchild = temp->lchild;
temp->lchild = root;
updateHeight(root);
updateHeight(temp);
root = temp;
}
void RightRotation(Node *&root) {
Node *temp = root->lchild;
root->lchild = temp->rchild;
temp->rchild = root;
updateHeight(root);
updateHeight(temp);
root = temp;
}
void insertNode(Node *&root, int value) {
if (root == NULL) {
root = new Node{value, 1, NULL, NULL};
} else if (value < root->value) {
insertNode(root->lchild, value);
updateHeight(root);
if (getBalanceFactor(root) == 2) {
if (getBalanceFactor(root->lchild) == 1) { //LL
RightRotation(root);
} else if (getBalanceFactor(root->lchild) == -1) { //LR
LeftRotation(root->lchild);
RightRotation(root);
}
}
} else if (value > root->value) {
insertNode(root->rchild, value);
updateHeight(root);
if (getBalanceFactor(root) == -2) {
if (getBalanceFactor(root->rchild) == -1) { //RR
LeftRotation(root);
} else if (getBalanceFactor(root->rchild) == 1) { //RL
RightRotation(root->rchild);
LeftRotation(root);
}
}
}
}
Node *createAVL(int n_node) {
Node *root = NULL;
int curr;
for (int i = 0; i < n_node; ++i) {
scanf("%d", &curr);
insertNode(root, curr);
}
return root;
}
int main() {
int nn;
scanf("%d", &nn);
Node *root = createAVL(nn);
printf("%d\n", root->value);
return 0;
}
网友评论