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

news/2025/2/24 7:11:30

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);
	}
}


http://www.niftyadmin.cn/n/5864066.html

相关文章

[特殊字符] Elasticsearch 双剑合璧:HTTP API 与 Java API 实战整合指南

&#x1f680; Elasticsearch 双剑合璧&#xff1a;HTTP API 与 Java API 实战整合指南 一、HTTP API 定义与用途 Elasticsearch 的 HTTP API 是基于 RESTful 接口设计的核心交互方式&#xff0c;支持通过 URL 和 JSON 数据直接操作索引、文档、集群等资源。适用于快速调试、…

前端VUE3框架的快速搭建

前端VUE3框架的快速搭建 安装nodejs创建一个 Vue 应用精简VUE项目在idea中运行vue项目修改标题定义全局css样式404页面 安装nodejs 参考&#xff1a;在MAC上面通过HomeBrew安装node和npm指定版本 https://blog.csdn.net/yu_fu_a_bu/article/details/145810229 vue3推荐使用 n…

基于 Python 的项目管理系统开发

基于 Python 的项目管理系统开发 一、引言 在当今快节奏的工作环境中&#xff0c;有效的项目管理对于项目的成功至关重要。借助信息技术手段开发项目管理系统&#xff0c;能够显著提升项目管理的效率和质量。Python 作为一种功能强大、易于学习且具有丰富库支持的编程语言&…

【行业解决方案十九】【DeepSeek汽车制造:焊接质量检测方案 】

在汽车制造领域,焊接质量直接关系到产品的安全性和可靠性。传统焊接检测方法不仅效率低下,还难以实现全面监控和质量问题的精准溯源。而如今,借助人工智能和大数据技术,DeepSeek 提供了一套全新的焊接质量检测方案,彻底改变了这一局面。 一、为什么焊接质量检测如此重要?…

通俗理解什么是云原生?

by deepseek。 一、核心理念&#xff1a;云原生到底是什么&#xff1f; 1. 一句话定义 云原生&#xff08;Cloud Native&#xff09; 是一种构建和运行应用程序的方法论&#xff0c;它利用云计算的优势&#xff08;弹性、分布式、自动化&#xff09;&#xff0c;让软件从设计…

动手学深度学习:线性回归神经网络

从零实现线性回归 生成数据 import torch def synthetic_data(w,b,num_examples):Xtorch.normal(0,1,(num_examples,len(w)))ytorch.matmul(X,w)bytorch.normal(0,0.1,y.shape)return X,y.reshape((-1,1)) true_wtorch.tensor([2,-3.4]).reshape(2,1) true_b4.2 features,lab…

第17篇:网络请求与Axios集成

目标&#xff1a;掌握在Vue3中规范地发起HTTP请求 1. 安装与基础配置 npm install axios // src/utils/request.js import axios from axios const service axios.create({ baseURL: https://api.example.com, timeout: 10000 }) export default service 2. 基础请…

正则表达式用法及其示例:匹配、查找、替换文本中的模式,及QT下如何使用正则表达式。

当然&#xff01;正则表达式是一种强大的工具&#xff0c;用于匹配、查找、替换文本中的模式。下面是一些常见的正则表达式用法及其示例。 1、基本语法 基本元字符和语法 .&#xff1a;匹配任意单个字符&#xff08;除了换行符&#xff09;。^&#xff1a;匹配输入字符串的开…