算法笔记---平衡二叉树(AVL)

71 篇文章 0 订阅
41 篇文章 3 订阅

平衡二叉树由前苏联两位数学家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);//根结点右旋
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值