平衡二叉搜索树(AVL树)

目录

二叉搜索树的缺点

将失调的二叉搜索树该能AVL树有以下这几种情况

第一种:左旋

第二种:右旋

什么时候会遇见失衡呢?失衡了应该怎么办呢?

LL型失衡(左旋)

LR型失衡(左旋+右旋)

RR型失衡(右旋)

RL型失衡(右旋+左旋)


二叉搜索树的缺点

我们现在有一个这样的二叉搜索树:

像这样的二叉搜索树,我们想找到50这个节点,我们用遍历5次,时间复杂度O(n),这样是不是就违背了我们用二叉搜索树的初衷呢,与其如此我还不如实现一个其他算法呢!!!这就是为什么我们要学习平衡二叉树

将失调的二叉搜索树该能AVL树有以下这几种情况

必要调整之后满足两个条件:1.是二叉搜索树  2.每个节点的平衡因子的绝对值应该小于等于1

第一种:左旋

修改方式:1.当前右子树会作为新树的根节点2.当前节点会作为新树根节点的左子树

3.如果原来右子树上有左节点,那左节点应该作为旧根的右节点

第二种:右旋

调整方式:1.当前左节点会成为新的根节点  2.旧根节点会作为新根节点的右孩子

3.如果原来左节点上有右节点,那么这个节点作为旧根节点的左孩子

什么时候会遇见失衡呢?失衡了应该怎么办呢?

LL型失衡(左旋)

但我们对一棵二叉搜索树进行插入元素的操作的时候见下图,如果我们在数值为20的节点上插入一个左节点,就成下面的那张图的样子,是不是就失衡了呢?我们用   左子树的深度-右子树的深度  看他的绝对值大小 下面那张图我们就对树进行右旋操作  应为失衡的原因是: root的左孩子Left的左子树Left ,我们也称这种失衡为LL型失衡

LR型失衡(左旋+右旋)

我们不向左节点去插入元素了,我们向20的右节点插入元素,就成下面这个图示的样子,我们向20的节点插入一个25的节点,我们发现这个二叉搜索树失衡了!!!root的左孩子Left的右子树Right导致失衡 ,那我们先左旋再右旋 我们称为LR型

我们先对20和25节点进行左旋

左旋完之后我们对整体进行右旋

RR型失衡(右旋)

当我们在40的右节点上插入一个节点50的时候,因为在根节点右子树的上的右节点上插入元素导致失衡,这叫RR型失衡,直接右旋就行了

RL型失衡(右旋+左旋)

当我们在上面的右节点40的左节点插入45,使得树不平衡,这是RL型失衡

遇见这种失衡,我们先右旋在左旋

我们先对35和40进行右旋,再对30,35,40进行左旋

我们看看代码

#include<iostream>
#include<string>
using namespace std;
struct TreeNode {
	int val;
	int height;
	struct TreeNode* left;
	struct TreeNode* right;
};
TreeNode* newNode(int data)
{
	TreeNode* node = new TreeNode();
	node->val = data;
	node->height = 1;
	node->left = NULL;
	node->right = NULL;
	return node;
}
//获取树的高度
int GetHeight(TreeNode* node)
{
	if (node == NULL)
	{
		return 0;
	}
	return node->height;
}
int max(int a, int b)
{
	return a > b ? a : b;
}
//定义左旋函数
TreeNode* leftRoate(TreeNode* root)
{
	 //当前节点的右子树会作为新树的根节点
	//当前节点会作为新树的根节点的左子树
	//如果新的树根原来有左子树,那么原来的左子树会作为旧根节点的右子树
	//*************************************************

    //当前节点的右子树会作为新树的根节点
	TreeNode* newroot = root->right;
	//如果新的树根原来有左子树
	//T2保存新树根原来的左子树
	TreeNode* T2 = newroot->left;
	//当前节点会作为新树的根节点的左子树
	newroot->left = root;
	//那么原来的左子树会作为旧根节点的右子树
	root->right = T2;

	//更新树高
	root->height = 1 + max(GetHeight(root->left), GetHeight(root->left));
	newroot->height = 1 + max(GetHeight(newroot->left), GetHeight(newroot->left));
	return newroot;
}

//定义右旋函数
//当前节点的左子树会作为新树的根节点
//当前节点会作为新树的根节点的右子树
//如果新的树根原来有右子树,那么原来的左子树会作为旧根节点的右子树
TreeNode* rightRotate(TreeNode* root)
{//当前节点的左子树会作为新树的根节点
	TreeNode* newroot = root->left;
	//如果新的树根原来有右子树,那么原来的左子树会作为旧根节点的右子树
	TreeNode* T2 = newroot->right;
	newroot->right = root;
	root->left = T2;
	//更新树高
	root->height = 1 + max(GetHeight(root->left), GetHeight(root->left));
	newroot->height = 1 + max(GetHeight(newroot->left), GetHeight(newroot->left));
	return newroot;
}
//定义函数,获取平衡因子
int getBalance(TreeNode* node)
{
	return GetHeight(node->left) - GetHeight(node->right);
}
//定义插入节点的函数
TreeNode* insertNode(TreeNode* node, int key)
{
	if (node == NULL)
		return newNode(key);
	if (key < node->val)
		node->left = insertNode(node->left, key);
	else if (key > node->val)
		node->right = insertNode(node->right, key);
	else
		return node;
	//更新树高
	node->height = 1 + max(GetHeight(node->left), GetHeight(node->right));
	//获取当前节点的平衡因子
	int balance = getBalance(node);
	//我们是否需要调整这个树,是看平衡因子是不是绝对值大于1
	//LL型失衡
	if (balance > 1 && getBalance(node->left) > 0)
	{
		return rightRotate(node);
	}
	//LR型失衡
	if (balance > 1 && getBalance(node->left) < 0)
	{
		node->left = leftRoate(node->left);
		return rightRotate(node);
	}
	//RR型失衡
	if (balance < -1 && getBalance(node->right) < 0)
	{
		return leftRoate(node);
	}
	//RL型失衡
	if (balance < -1 && getBalance(node->right)>0)
	{
		node->right = rightRotate(node->right);
		return leftRoate(node);
	}
	return node;
}
TreeNode* find(TreeNode* root, int key, int* counter)
{
	TreeNode* cur = root;
	while (cur != NULL)
	{
		if (key < cur->val)
		{
			cur = cur->left;
			(*counter)++;
		}
		else if (key > cur->val)
		{
			cur = cur->right;
			(*counter)++;
		}
		else {
			(*counter)++;
			return cur;
		}
	}
	return NULL;
}
//先序遍历
void preOrder(TreeNode* root)
{
	if (root == NULL)
	{
		cout << "NULL" << " ";
		return;
	}
	cout << root->val << " ";
	preOrder(root->left);
	preOrder(root->right);
}
void Inorder(TreeNode* root)
{
	if (root == NULL)
	{
		cout << "NULL" << " ";
		return;
	}
	Inorder(root->left);
	cout << root->val << " ";
	Inorder(root->right);
}

void test()
{
	TreeNode* root = NULL;
	root = insertNode(root, 10);
	root = insertNode(root, 20);
	root = insertNode(root, 30);
	root = insertNode(root, 40);
	root = insertNode(root, 50);
	root = insertNode(root, 60);
	root = insertNode(root, 70);
	int counter = 0;
	TreeNode* result = find(root, 70, &counter);
	cout << counter << endl;
	cout << "前序打印结果" << endl;
	preOrder(root);
	cout << endl;
	cout << "中序打印结果" << endl;
	Inorder(root);
}
int main()
{
	test();
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值