提高篇-平衡二叉树AVL-《算法笔记》同步笔记总结与补充

专题要点:

平衡二叉树(AVL)是更优的二叉搜索树,其难度在于构造上,且查找方式与二叉搜索树一致。
AVL的复杂程度,单靠死记硬背压根是不可能的,需要理解记忆。借此文章帮助自己梳理一下。

AVL树构建过程:

  • 首先,平衡二叉树的特点在于引入了平衡因子这一特性,因此需要在数据结构中加入高度成员变量,通过高度计算节点的平衡因子
  • 其次,由于AVL对平衡因子有严格限制(高度之差的绝对值不超过1),因此在插入过程中需要对树型不断进行调整来满足对平衡因子的要求
  • 再次,引入左旋右旋两种调整树型的措施,两种方式在插入节点时相互配合,完成对根节点和子节点在不同平衡因子情形下旋转调整。
  • 最后,根据根节点和子节点的平衡因子不同,将树型分为LL, LR, RR, RL四种树型,每种树型有各自的调整方式

树型判断

树型判定条件调整方法
LLBF(root)=2,BF(root->left)=1对root进行右旋
LRBF(root)=2,BF(root->left)=-1先对root->left进行左旋,再对root进行右旋
RRBF(root)=-2,BF(root->right)=-1对root进行左旋
RLBF(root)=-2,BF(root->right)=1先对root->right进行右旋,再对root进行右旋

注:BF(root)表示root的平衡因子

记忆点

  • 通过节点高度,计算节点平衡因子
  • 通过节点高度,简介求出根的高度(即,左右子树的最大值 + 1)
  • 过程中不断更新节点高度
  • 左旋=>向左旋转=>逆时针;右旋=>向右旋转=>顺时针
  • 左旋右旋是互逆操作(过程分为三个步骤,两次更新,画图理解也不是很容易理解,这就很难受了!)
  • 四种树型和其相应的四种调整方式

本人至今未找到合适的记忆方法,实在是不好理解,个人编程在实现左旋右旋,以及树型判断和其相应的左旋右旋操作上还是有困难

编程实现:

数据结构

struct Node{
	int data;
	int height;//当前子树的高度
	Node* left;
	Node* right; 
};

相关函数

函数名称函数类型函数参数函数作用
newNodeNode*x:节点数据域新建节点
getHeightintroot:节点指针获取节点的高度
getBalanceFactorintroot:节点指针获取节点的平衡因子
updateHeightvoidroot:节点指针通过子节点高度,更新根节点的高度
LRotationvoid&root:节点指针引用左旋
RRotationvoid&root:节点指针引用右旋
insertvoid&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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值