C++实现AVL树


在这里插入图片描述


先赞后看,养成习惯!!!^ _ ^<3 ❤️ ❤️ ❤️
码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了关注我哦!
所属专栏:C++进阶

在这里插入图片描述

一、平衡树的优势

经过了解二叉搜索树的性质之后,我们也发现了它极大的缺陷,如果数字基本上都是趋于有序的情况下,那么查找效率非常低下,时间复杂度为O(n),与顺序表的查找一样,因此我们引出了二叉平衡搜索树(AVL树),该树的优势在于能够保证根节点左右子树的高度差的绝对值小于等于1,这就很好保证了查找效率O(logn),如下图就是二叉平衡搜索树的样子。
在这里插入图片描述

二、二叉平衡搜索树的节点定义

由于二叉平衡搜索树需要对节点进行旋转,我们这里引入了父节点的指针,还有平衡因子(保证节点处于平衡状态)
在这里插入图片描述

三、二叉搜索树的插入

3.1 寻找插入位置

首先插入顺序还是和二叉搜索树大差不差,有区别的位置是需要判断平衡因子是否大于1,大于1就要开始旋转了(这里就略过,需要看具体操作可以看二叉搜索树那一章)
在这里插入图片描述

3.2 开始判定平衡因子,平衡因子有变就开始旋转

3.2.1 左旋的情况

在这里插入图片描述

在这里插入图片描述

3.2.2 左旋代码(一定要考虑平衡因子为2或者-2的节点是否有父节点)

在这里插入图片描述

3.2.2 右旋的情况

在这里插入图片描述
在这里插入图片描述

3.2.3 左右双旋的情况(细分为3种情况)
3.2.3.1 以下为例3的左子树为h时

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一定要注意平衡因子的变化

3.2.3.2 以下为例3的右子树为h时

在这里插入图片描述
在这里插入图片描述

3.2.3.3 如果3的右子树为空时

那么平衡因子都为0,其他变化都是一样的

3.2.3.4 代码演示

在这里插入图片描述

3.2.4 右左双旋的情况(一样细分三种情况)

下面只讲解一种情况其他都是一样的就是平衡因子发生改变

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、平衡树的检验(是否平衡)

4.1 先从高度方面检验

在这里插入图片描述

4.2 再看树的节点个树

在这里插入图片描述

4.3 最后看树的平衡因子

在这里插入图片描述

五、全部源码

#pragma once
#include<iostream>
#include<vector>
#include<assert.h>
//#include <utility> 
using namespace std;
template<class K,class V>
struct AVLTreeNode
{
	AVLTreeNode<K,V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	int _bf;
	pair<K, V> _kv;

	//构造函数初始化列表
	AVLTreeNode(const pair<K, V> kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _bf(0)
		, _kv(kv)
	{}
};

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	bool Insert(const pair<K,V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(kv);

		if (parent->_kv.first > kv.first)
			parent->_left = cur;
		else
			parent->_right = cur;

		cur->_parent = parent;

		while (parent)
		{
			if (cur == parent->_left)
			{
				parent->_bf--;//左为减
			}
			else
			{
				parent->_bf++;
			}

			if (parent->_bf == 1 || parent->_bf == -1)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				if (parent->_bf == 2 && cur->_bf == 1)
				{
					RotateL(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == -1)
				{
					RotateR(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					RotateLR(parent);
				}
				else
				{
					RotateRL(parent);
				}
				break;
			}
		}
		return true;
	}

	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		if (subRL)
			subRL->_parent = parent;

		parent->_right = subRL;
		Node* pp = parent->_parent;
		subR->_left = parent;

		if (pp == nullptr)
		{
			parent->_parent = subR;
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (pp->_left == parent)
			{
				parent->_parent = subR;
				subR->_parent = pp;
				pp->_left = subR;
			}
			else if (pp->_right == parent)
			{
				parent->_parent = subR;
				pp->_right = subR;
				subR->_parent = pp;
			}
			else
			{
				assert(false);
			}
		}
		parent->_bf = subR->_bf = 0;
	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		if (subLR)
			subLR->_parent = parent;

		parent->_left = subLR;
		Node* pp = parent->_parent;
		subL->_right = parent;

		if (pp == nullptr)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (pp->_left == parent)
			{
				parent->_parent = subL;
				subL->_parent = pp->_left;
			}
			else if (pp->_right = parent)
			{
				parent->_parent = subL;
				subL->_parent = pp->_right;
			}
			else
			{
				assert(false);
			}
		}
		parent->_bf = subL->_bf = 0;
	}

	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		int bf = subLR->_bf;
		RotateL(subL);
		RotateR(parent);

		if (bf == -1)
		{
			parent->_bf = -1;
			subLR->_bf = 0;
			subL->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = 0;
			subLR->_bf = 0;
			subL->_bf = 1;
		}
		else if (bf == 0)
		{
			parent->_bf = subLR->_bf = subL->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		int bf = subRL->_bf;

		RotateR(subR);
		RotateL(parent);

		if (bf == -1)
		{
			parent->_bf = 0;
			subRL->_bf = 0;
			subR->_bf = 1;
		}
		else if (bf == 1)
		{
			parent->_bf = -1;
			subRL->_bf = 0;
			subR->_bf = 0;
		}
		else if (bf == 0)
		{
			parent->_bf = subRL->_bf = subR->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

	void _Inorder()
	{
		Inorder(_root);
	}

	void Inorder(Node* root)
	{
		if (root == nullptr)
			return;

		Inorder(root->_left);
		cout << root->_kv.first << endl;
		Inorder(root->_right);
	}

	Node* Find(const pair<K,V> kv)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first > kv.first)
			{
				cur = cur->_left;
			}
			else if (cur->_kv.first < kv.first)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

	size_t _Height()//树的高度
	{
		return Height(_root);
	}

	size_t Height(Node* root)
	{
		if (root == nullptr)
			return 0;

		int leftHeight = Height(root->_left);
		int rightHeight = Height(root->_right);
		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}

	//数的节点个树
	size_t _Size()
	{
		return Size(_root);
	}

	size_t Size(Node* root)
	{
		if (root == nullptr)
			return 0;

		return Size(root->left) + Size(root->right) + 1;
	}

	//判断树是否平衡
	bool _Isbalance()
	{
		return Isbalance(_root);
	}



	bool Isbalance(Node* root)
	{
		if (root == nullptr)
			return false;

		int leftHeight = Height(root->_left);
		int rightHeight = Height(root->_right);
		return abs(leftHeight - rightHeight) < 2
			&& Isbalance(root->_left) && Isbalance(root->_right);//检查完当前树的高度
		//然后就检查当前树的左子树和右子树是否符合要求
	}

private:
	Node* _root = nullptr;

};

在这里插入图片描述

  • 32
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
AVL树的插入和删除操作都需要对树进行旋转操作来保持AVL树的平衡性。下面是C语言实现AVL树插入和删除操作: AVL树插入操作: ```c // AVL树节点定义 struct AVLNode { int key; int height; struct AVLNode* left; struct AVLNode* right; }; // 计算节点高度 int height(struct AVLNode* node) { if (node == NULL) { return 0; } return node->height; } // 右旋操作 struct AVLNode* rotate_right(struct AVLNode* y) { struct AVLNode* x = y->left; struct AVLNode* t2 = x->right; // 执行旋转 x->right = y; y->left = t2; // 更新高度 y->height = max(height(y->left), height(y->right)) + 1; x->height = max(height(x->left), height(x->right)) + 1; return x; } // 左旋操作 struct AVLNode* rotate_left(struct AVLNode* x) { struct AVLNode* y = x->right; struct AVLNode* t2 = y->left; // 执行旋转 y->left = x; x->right = t2; // 更新高度 x->height = max(height(x->left), height(x->right)) + 1; y->height = max(height(y->left), height(y->right)) + 1; return y; } // 计算平衡因子 int balance_factor(struct AVLNode* node) { if (node == NULL) { return 0; } return height(node->left) - height(node->right); } // 插入节点 struct AVLNode* avl_insert(struct AVLNode* node, int key) { // 执行BST插入 if (node == NULL) { struct AVLNode* new_node = (struct AVLNode*)malloc(sizeof(struct AVLNode)); new_node->key = key; new_node->height = 1; new_node->left = NULL; new_node->right = NULL; return new_node; } if (key < node->key) { node->left = avl_insert(node->left, key); } else if (key > node->key) { node->right = avl_insert(node->right, key); } else { // key已经存在,不需要插入 return node; } // 更新高度 node->height = max(height(node->left), height(node->right)) + 1; // 计算平衡因子 int bf = balance_factor(node); // 如果平衡因子大于1,需要进行旋转操作 if (bf > 1) { if (key < node->left->key) { // 左左情况,执行右旋操作 return rotate_right(node); } else { // 左右情况,先对左子树进行左旋操作,再对根节点进行右旋操作 node->left = rotate_left(node->left); return rotate_right(node); } } else if (bf < -1) { if (key > node->right->key) { // 右右情况,执行左旋操作 return rotate_left(node); } else { // 右左情况,先对右子树进行右旋操作,再对根节点进行左旋操作 node->right = rotate_right(node->right); return rotate_left(node); } } return node; } ``` AVL树删除操作: ```c // 查找最小值节点 struct AVLNode* find_min(struct AVLNode* node) { if (node == NULL) { return NULL; } if (node->left == NULL) { return node; } return find_min(node->left); } // 删除节点 struct AVLNode* avl_delete(struct AVLNode* node, int key) { // 执行BST删除 if (node == NULL) { return NULL; } if (key < node->key) { node->left = avl_delete(node->left, key); } else if (key > node->key) { node->right = avl_delete(node->right, key); } else { if (node->left == NULL || node->right == NULL) { // 被删除节点只有一个子节点或者没有子节点 struct AVLNode* temp = node->left ? node->left : node->right; if (temp == NULL) { // 没有子节点,直接删除 temp = node; node = NULL; } else { // 有一个子节点,用子节点替换被删除节点 *node = *temp; } free(temp); } else { // 被删除节点有两个子节点,找到右子树的最小值节点替换被删除节点 struct AVLNode* temp = find_min(node->right); node->key = temp->key; node->right = avl_delete(node->right, temp->key); } } if (node == NULL) { return NULL; } // 更新高度 node->height = max(height(node->left), height(node->right)) + 1; // 计算平衡因子 int bf = balance_factor(node); // 如果平衡因子大于1,需要进行旋转操作 if (bf > 1) { if (balance_factor(node->left) >= 0) { // 左左情况,执行右旋操作 return rotate_right(node); } else { // 左右情况,先对左子树进行左旋操作,再对根节点进行右旋操作 node->left = rotate_left(node->left); return rotate_right(node); } } else if (bf < -1) { if (balance_factor(node->right) <= 0) { // 右右情况,执行左旋操作 return rotate_left(node); } else { // 右左情况,先对右子树进行右旋操作,再对根节点进行左旋操作 node->right = rotate_right(node->right); return rotate_left(node); } } return node; } ``` 以上是AVL树的插入和删除操作的C语言实现。需要注意的是,AVL树的插入和删除操作都需要对树进行旋转操作来保持平衡,因此这些操作的时间复杂度是O(log n)。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙猫不是一只猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值