平衡二叉树由前苏联两位数学家GM.Adelse-Velskil和E.M.Landis提出,因此一般也称作AVL树。
AVL树仍然是一棵二叉查找树,只是在其基础上增加了“平衡”的要求。所谓平衡是指,对AVL树的任意结点来说,其左子树与右子树的高度之差的绝对值不超过1,其中左子树与右子树的高度之差称为该结点的平衡因子。
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
struct node
{
int data;//结点权值
int height;//以当前结点为根的子树的高度
node* lchild;//左孩子
node* rchild;//右孩子
};
//建立一个新结点
node* new_node(int data) {
node* newNode = new node;
newNode->data = data;
newNode->lchild = newNode->rchild = NULL;
newNode->height = 1;
return newNode;
}
//返回以当前结点为根的子树的高度
int get_height(node* root) {
if (root == NULL)
{
return 0;
}
return root->height;
}
//计算结点 root 的平衡因子
int get_balance_factor(node* root) {
return get_height(root->lchild) - get_height(root->rchild);
}
//更新root结点的height
void update_height(node* root) {
root->height = max(get_height(root->lchild), get_height(root->rchild)) + 1;
}
//左旋
void left_rotation(node* &root) {
node* temp = root->rchild;//A (root)的右子树 B
root->rchild = temp->lchild;//B 的右子树作为 A 的左子树
temp->lchild = root;//A 作为 B 的左子树
update_height(root); //更新 A 结点的高度
update_height(temp); //更新 B 结点的高度
root = temp;//B 作为根结点
}
//右旋
void right_rotation(node*& root) {
node* temp = root->lchild;
root->lchild = temp->rchild;
temp->rchild = root;
update_height(root);
update_height(temp);
root = temp;
}
//平衡二叉树的插入
void insert(node* &root, int data) {
if (root == NULL)//当前结点为空
{
root = new_node(data);
return;
}
if (root->data < data)//当前结点小于待插入结点,则在右子树插入
{
insert(root->rchild, data);
update_height(root);//更新树的高度
if (get_balance_factor(root) == -2)
{
if (get_balance_factor(root->rchild) == -1)//RR型
{
left_rotation(root);//根结点左旋
}else if (get_balance_factor(root->rchild) == 1)//RL型
{
right_rotation(root->rchild);//右子树右旋
left_rotation(root);//根结点左旋
}
}
}
else//当前结点大于待插入结点,则在左子树插入
{
insert(root->lchild, data);
update_height(root);
if (get_balance_factor(root) == 2)
{
if (get_balance_factor(root->lchild) == 1)//LL型
{
right_rotation(root);
}else if (get_balance_factor(root->lchild) == -1)//LR型
{
left_rotation(root->lchild);//左子树左旋
right_rotation(root);//根结点右旋
}
}
}
}
//构造一棵平衡二叉树
node* create_avl_tree(vector<int> v) {
node* root = NULL;
for (int i = 0;i < v.size(); i++)
{
insert(root, v[i]);//将v中的数字插入 AVL 树中
}
return root;//返回根结点
}
//层序遍历
void avl_bfs(node* root) {
if (root == NULL)
{
return;
}
queue<node*> q;
q.push(root);
while (!q.empty())
{
node* top = q.front();
q.pop();
cout << top->data << endl;
if (top->lchild)
{
q.push(top->lchild);
}
if (top->rchild)
{
q.push(top->rchild);
}
}
}
int main() {
vector<int> v;
for (int i = 1;i < 6;i++)
{
v.push_back(i);
}
node* root = create_avl_tree(v);
avl_bfs(root);
system("pause");
return 0;
}
按照 层序遍历 输出:
左旋:
图片来源于算法笔记
//左旋
void left_rotation(node* &root) {
node* temp = root->rchild;//A (root)的右子树 B
root->rchild = temp->lchild;//B 的右子树作为 A 的左子树
temp->lchild = root;//A 作为 B 的左子树
update_height(root); //更新 A 结点的高度
update_height(temp); //更新 B 结点的高度
root = temp;//B 作为根结点
}
右旋:
图片来源于算法笔记
//右旋
void right_rotation(node*& root) {
node* temp = root->lchild;
root->lchild = temp->rchild;
temp->rchild = root;
update_height(root);
update_height(temp);
root = temp;
}
可以发现,左旋和右旋相对称,左旋只需要将代码中的左右子树(lchild和rchild)对调,即可变成右旋。
平衡二叉树的调整:
图片来自于算法笔记
//平衡二叉树的插入
void insert(node* &root, int data) {
if (root == NULL)//当前结点为空
{
root = new_node(data);
return;
}
if (root->data < data)//当前结点小于待插入结点,则在右子树插入
{
insert(root->rchild, data);
update_height(root);//更新树的高度
if (get_balance_factor(root) == -2)
{
if (get_balance_factor(root->rchild) == -1)//RR型
{
left_rotation(root);//根结点左旋
}else if (get_balance_factor(root->rchild) == 1)//RL型
{
right_rotation(root->rchild);//右子树右旋
left_rotation(root);//根结点左旋
}
}
}
else//当前结点大于待插入结点,则在左子树插入
{
insert(root->lchild, data);
update_height(root);
if (get_balance_factor(root) == 2)
{
if (get_balance_factor(root->lchild) == 1)//LL型
{
right_rotation(root);
}else if (get_balance_factor(root->lchild) == -1)//LR型
{
left_rotation(root->lchild);//左子树左旋
right_rotation(root);//根结点右旋
}
}
}
}