当前位置: 首页 > news >正文

C++ ——— 模拟实现 AVL 树的插入

AVL 树的概念

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度

AVL 树的特征:

1. 它的左右子树都是 AVL 树

2. 左右子树的高度之差(简称平衡因子)的绝对值不超过 1 

图形演示:

拿节点 3 举例:
节点 3 的左节点的高度为 3,右节点的高度为 2,那么节点 3 的 -1 是 2 减去 3 得来的,所以可以看出是右节点的高度减去左节点的高度

节点 7 也是同样的道理:
节点 7 的左节点高度为 2,右节点高度为 3,3减去2 就是节点 7 的平衡因子


节点的定义

template<class K, class V>
struct AVLTreeNode
{
	AVLTreeNode(const pair<K,V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _bf(0)
	{}

	AVLTreeNode<K, V>* _left;    //指向该节点的左孩子
	AVLTreeNode<K, V>* _right;   //指向该节点的右孩子
	AVLTreeNode<K, V>* _parent;  //指向该节点的父亲节点

	pair<K, V> _kv; //存储

	int _bf; //平衡因子
};

将单个节点设置为KV结构,并且不能出现相同的K 


AVL 树的定义

template<class K, class V>
class AVLTree
{
	typedef AVLTree<K, V> Node;

public:
	// ...

private:
	Node* _root = nullptr;
};

插入

bool Insert(const pair<K,V>& kv)
{
	//当为空树时
	if (_root == nullptr)
	{
		// 直接链接
		_root = new Node(kv);
		return true;
	}

	// 不为空树时,先找到合适的位置插入
	Node* parent = nullptr;
	Node* cur = _root;

	while (cur != nullptr)
	{
		// 左小右大
		if (cur->_kv.first > kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (cur->_kv.first < kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			// 说明有相同的key,直接返回 false
			return false;
		}
	}

	// 走到这里表示走到空了,可以插入了
	cur = new Node(kv);
	if (parent->_bf.first > kv.first)
	{
		// 说明父亲节点的值大于key,那么就插入到左边
		parent->_left = cur;
	}
	else
	{
		// 否则就插入到右边
		parent->_right = cur;
	}
	// 并且与父亲节点链接
	cur->_parent = parent;

	/* 插入完成后,管控平衡 */
	while (parent != nullptr)
	{
		// 左减右加
		if (cur == parent->_left)
		{
			parent->_bf++;
		}
		else
		{
			parent->_bf--;
		}

		// 判断平衡因子的状态
		if (parent->_bf == 0)
		{
			// 说明左右平衡
			break;
		}
		else if (parent->_bf == -1 || parent->_bf == 1)
		{
			// 向上调整祖先平衡因子的状态
			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)
			{
				RotateRL(parent);
			}
			else if (parent->_bf == -2 && cur->_bf == 1)
			{
				RotateLR(parent);
			}
			else
			{
				assert(false);
			}

			break;
		}
		else
		{
			assert(false);
		}

	}

	return true;
}
// 左单旋
void RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	Node* parentParent = parent->_parent;

	parent->_right = subRL;
	if(subRL != nullptr)
		subRL->_parent = parent;

	subR->_left = parent;
	parent->_parent = subR;
	if (_root == parent)
	{
		_root = subR;
		_root->_parent = nullptr;
	}
	else
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = subR;
		}
		else
		{
			parentParent->_right = subR;

		}

		subR->_parent = parentParent;
	}

	// 更新平衡因子
	parent->_bf = subR->_bf = 0;
}
// 右单旋
void RotateR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	Node* parentParent = parent->_parent;

	parent->_left = subLR;
	if(subLR != nullptr)
		subLR->_parent = parent;

	subL->_right = parent;
	parent->_parent = subL;
	if (parent == _root)
	{
		_root = subL;
		_root->_parent = nullptr;
	}
	else
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = subL;
		}
		else
		{
			parentParent->_right = subL;
		}

		subL->_parent = parentParent;
	}

	// 更新平衡因子
	parent->_bf = subL->_bf = 0;
}
// 右左双旋
void RotateRL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	int bf = subRL->_bf;

	RotateR(parent->_right);
	RotateL(parent);

	if (bf == 0)
	{
		parent->_bf = subR->_bf = subRL->_bf = 0;
	}
	else 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
	{
		assert(false);
	}
}
// 左右双旋
void RotateLR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	int bf = subLR->_bf;

	RotateL(parent->_left);
	RotateR(parent);

	if (bf == 0)
	{
		parent->_bf = subL->_bf = subLR->_bf = 0;
	}
	else 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
	{
		assert(false);
	}
}

相关文章:

  • Win10配置VSCode的C/C++编译环境
  • 前后端分离系统架构:基于Spring Boot的最佳实践
  • 基于AT89C52单片机的出租车计价器
  • 【Linux进程一】进程的概念
  • CUDA专题1:CUDA介绍
  • Docker启动ES容器打包本地镜像
  • 基于RISC-V内核完全自主可控国产化MCU芯片
  • Shell脚本和Bat脚本区别
  • 我的世界地下城DLC开发的第二天
  • 第9章:LangChain结构化输出-示例2(数字提取服务)
  • 公开整理-最新中国城市统计NJExcel+PDF版本(1985-2024年)
  • B. Skibidus and Ohio
  • DeepSheek 本地部署
  • Service Worker 实现离线应用思路
  • 简识Kafka集群与RocketMQ集群的核心区别
  • 网络安全研究
  • 在运维工作中,磁盘文件满了,怎么办?
  • 綫性與非綫性泛函分析與應用_2.賦范向量空間-母本
  • Java——抽象类
  • 快速排序与归并排序模板
  • 成都建设网站哪家好/医院网络销售要做什么
  • 绍兴专业做网站的公司/独立网站怎么做
  • 网站源码下载地址是什么/外贸推广引流
  • 厦门网站建设公司哪个好/软件推广怎么赚钱
  • 如何做淘客网站/新闻早知道
  • 微信网站 微信支付/惠州seo关键词