专题要点:
平衡二叉树(AVL)是更优的二叉搜索树,其难度在于构造上,且查找方式与二叉搜索树一致。
AVL的复杂程度,单靠死记硬背压根是不可能的,需要理解记忆。借此文章帮助自己梳理一下。
AVL树构建过程:
- 首先,平衡二叉树的特点在于引入了平衡因子这一特性,因此需要在数据结构中加入高度成员变量,通过高度计算节点的平衡因子
- 其次,由于AVL对平衡因子有严格限制(高度之差的绝对值不超过1),因此在插入过程中需要对树型不断进行调整来满足对平衡因子的要求
- 再次,引入左旋右旋两种调整树型的措施,两种方式在插入节点时相互配合,完成对根节点和子节点在不同平衡因子情形下旋转调整。
- 最后,根据根节点和子节点的平衡因子不同,将树型分为LL, LR, RR, RL四种树型,每种树型有各自的调整方式
树型判断
树型 | 判定条件 | 调整方法 |
---|---|---|
LL | BF(root)=2,BF(root->left)=1 | 对root进行右旋 |
LR | BF(root)=2,BF(root->left)=-1 | 先对root->left进行左旋,再对root进行右旋 |
RR | BF(root)=-2,BF(root->right)=-1 | 对root进行左旋 |
RL | BF(root)=-2,BF(root->right)=1 | 先对root->right进行右旋,再对root进行右旋 |
注:BF(root)表示root的平衡因子
记忆点
- 通过节点高度,计算节点平衡因子
- 通过节点高度,简介求出根的高度(即,左右子树的最大值 + 1)
- 过程中不断更新节点高度
- 左旋=>向左旋转=>逆时针;右旋=>向右旋转=>顺时针
- 左旋右旋是互逆操作(过程分为三个步骤,两次更新,画图理解也不是很容易理解,这就很难受了!)
- 四种树型和其相应的四种调整方式
本人至今未找到合适的记忆方法,实在是不好理解,个人编程在实现左旋右旋,以及树型判断和其相应的左旋右旋操作上还是有困难
编程实现:
数据结构
struct Node{
int data;
int height;//当前子树的高度
Node* left;
Node* right;
};
相关函数
函数名称 | 函数类型 | 函数参数 | 函数作用 |
---|---|---|---|
newNode | Node* | x:节点数据域 | 新建节点 |
getHeight | int | root:节点指针 | 获取节点的高度 |
getBalanceFactor | int | root:节点指针 | 获取节点的平衡因子 |
updateHeight | void | root:节点指针 | 通过子节点高度,更新根节点的高度 |
LRotation | void | &root:节点指针引用 | 左旋 |
RRotation | void | &root:节点指针引用 | 右旋 |
insert | void | &root:节点指针引用;x:插入的数据 | 插入节点,递归建树 |
代码:
#include <bits/stdc++.h>
using namespace std;
int N;
struct Node{
int data;
int height;//当前子树的高度
Node* left;
Node* right;
};
Node* newNode(int x)
{
Node* node = new Node;
node->data = x;
node->height = 1;//初始高度为1
node->left = node->right = NULL;
return node;
}
int getHeight(Node* root)
{
if(root == NULL)
return 0;
else
return root->height;
}
int getBalanceFactor(Node* root)
{
return (getHeight(root->left) - getHeight(root->right));
}
void updateHeight(Node* root)
{
root->height = max(getHeight(root->left), getHeight(root->right)) + 1;
}
void LRotation(Node* &root)
{
Node* temp = root->right;
root->right = temp->left;
temp->left = root;
updateHeight(root);
updateHeight(temp);
root = temp;
}
void RRotation(Node* &root)
{
Node* temp = root->left;
root->left = temp->right;
temp->right = root;
updateHeight(root);
updateHeight(temp);
root = temp;
}
//根节点,要插入的值为x
void insert(Node* &root, int x)
{
if(root == NULL)
{
root = newNode(x);
return;
}
if(x < root->data)
{
insert(root->left, x);
updateHeight(root);
if(getBalanceFactor(root) == 2)
{
if(getBalanceFactor(root->left) == 1)
{
RRotation(root);
}
else if(getBalanceFactor(root->left) == -1)
{
LRotation(root->left);
RRotation(root);
}
}
}
else
{
insert(root->right, x);
updateHeight(root);
if(getBalanceFactor(root) == -2)
{
if(getBalanceFactor(root->right) == -1)
{
LRotation(root);
}
else if(getBalanceFactor(root->right) == 1)
{
RRotation(root->right);
LRotation(root);
}
}
}
}
int main(int argc, char *argv[]) {
scanf("%d", &N);
Node* root = NULL;
for(int i = 0; i < N; ++i)
{
int x;
scanf("%d", &x);
insert(root, x); //建树
}
return 0;
}