C++语法(19)---- 模拟AVL树

news2024/10/2 12:27:26

C++语法(18)---- set和map_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130228232?spm=1001.2014.3001.5501

 目录

1.AVL树的概念

2.节点定义

3.AVL树的类实现

1.类定义

2.insert

1.全代码实现

2.思考角度

3.平衡因子的情况

4.调节平衡的旋转

3.Print

4.Check

1. 验证其为二叉搜索树

2. 验证其为平衡树


1.AVL树的概念

1.普通搜索二叉树的插入可能会出现退化变为单支树,这样查找的效率就变为了O(N)

2.AVL树是当插入新的节点时,保证每个节点的左右子树的高度差绝对值不超过1

3.AVL树的平衡实现是通过调整高度得到的

特征

1.左右子树也是AVL树

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

2.节点定义

template<class K,class V>
struct AVLTreeNode
{
	pair<K,V> _kv;
	AVLTreeNode* _left;
	AVLTreeNode* _right;
	AVLTreeNode* _parent;
	int _bf;

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

1.搜索二叉树实现只传入让K,V直接当数据

2.AVL树中使用pair来进行合并K和V数据

3.节点为三叉节点,指向孩子和父亲节点

4._bf为平衡因子,这样直观表示是否平衡,根据因子进行调整

5.要记得初始化节点,这样下面实现才能用

3.AVL树的类实现

1.类定义

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K,V> Node;
private:
	Node* _root = nullptr;
};

2.insert

1.先跟搜索二叉树的实现一样,插入到对应的位置

2.更新平衡因子

3.通过因子判断是否进行平衡调节 

1.全代码实现

bool Insert(const pair<K, V>& kv)
{
    //1.先跟搜索二叉树的实现一样,插入到对应的位置
	if (_root == nullptr)
	{
		_root = new Node(kv);
		return true;
	}

	//父子节点确定插入的位置
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
        //比cur要小,往cur的左边走
		if (cur->_kv.first > kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
        //比cur要大,往cur的右边走
		else if (cur->_kv.first < kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
        //相同,不插入
		else
			return false;
	}

    //走到这cur就是要插入的位置
	//cur要连接parent,parent也要连接cur---判断靠kv的大小

	cur = new Node(kv);
	if (parent->_kv.first > cur->_kv.first)
	{
		parent->_left = cur;
		cur->_parent = parent;
	}
	else
	{
		parent->_right = cur;
		cur->_parent = parent;
	}

    //2.更新平衡因子
	while (parent)
	{
		//左减右加
		if (parent->_left == cur)
		{
			parent->_bf--;
		}
		else if (parent->_right == cur)
		{
			parent->_bf++;
		}

	    //情况一_bf如果等于0,说明之前是 1/-1,说明现在加进去不会影响原来的平衡,退出就行
	    if (parent->_bf == 0)
		    break;

	    //如果等于1/-1,说明之前没有树,加进去就多一个高度 -- 判断祖先节点的_bf(通过循环)
	    else if (parent->_bf == 1 || parent->_bf == -1)
	    {
		    cur = parent;
			parent = parent->_parent;
		}
        //如果等于2/-2,说明这个节点下面要调整
		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 if (parent->_bf == 2 && cur->_bf == -1)
			{
				_RotateRL(parent);
			}
			else
			{
				assert(false);
			}
			break;
		}
		else
		{
			assert(false);
		}
	}
	return true;
}

2.思考角度

思想的前提:不要认为这个算法是用来使得已有搜索二叉树变平衡,而是加一个节点进行调节每一次加入该树都是平衡搜索二叉树。

3.平衡因子的情况

情况一子树的高度不变,上面的也不会影响

情况二可能会更新到跟节点,所以我们可能需要持续的更新,所以需要向上检测

4.调节平衡的旋转

1.旋转的目的

1.必须将这颗子树变成左右高度差绝对值不超过1

2.不允许其他位置的高度

3.更新平衡因子

4.降低子树的高度

2.旋转的情况

1.左单旋

60右边变成30左边,60左边变成30;60和30的平衡因子变为0

void _RotateL(Node*& parent)
{
	Node* pparent = parent->_parent;
	Node* SubR = parent->_right;
	Node* SubRL = SubR->_left;
	if (pparent == nullptr)
	{
		_root = SubR;
		SubR->_parent = nullptr;
	}
	else
	{
		if (pparent->_left == parent)
			pparent->_left = SubR;
		else
			pparent->_right = SubR;
		SubR->_parent = pparent;
	}
	parent->_parent = SubR;
	SubR->_left = parent;
	parent->_right = SubRL;
	if (SubRL != nullptr)
		SubRL->_parent = parent;
	parent->_bf = 0;
	SubR->_bf = 0;
}

2.右单旋

void _RotateR(Node*& parent)
{
	Node* pparent = parent->_parent;
	Node* SubL = parent->_left;
	Node* SubLR = SubL->_right;
	if (pparent == nullptr)
	{
		_root = SubL;
		SubL->_parent = nullptr;
	}
	else
	{
		if (pparent->_left == parent)
			pparent->_left = SubL;
		else
			pparent->_right = SubL;
		SubL->_parent = pparent;
	}
	parent->_parent = SubL;
	SubL->_right = parent;
	parent->_left = SubLR;
	if (SubLR != nullptr)
		SubLR->_parent = parent;
	parent->_bf = 0;
	SubL->_bf = 0;
}

 3.先右单旋再左单旋

虽说右单旋再左单旋就完成了对应的结构,但这些节点的平衡因子是被打乱的;

从结果上看,其实就是将最60的左右子树平分给它父节点和“爷爷”节点

60的平衡因子不管怎么样都是0是确定的

但是另外两个节点平衡因子是看原先60的平衡因子:

b为h的话,30平衡因子为0,90的平衡因子为1

c为h的话,30平衡因子为-1,90的平衡因子为0

因此,我们需要一个临时平衡因子tmp_bf存储60位置的平衡因子

60是新增节点,那么30和90的平衡因子都是0了

60的子数是新增,那需要看这个临时因子

void _RotateRL(Node*& parent)
{
	Node* SubR = parent->_right;
	Node* SubRL = SubR->_left;
	int tmp_bf = 0;
	 if (SubRL->_left == nullptr && SubRL->_right == nullptr)
		tmp_bf = 0;
	else
		tmp_bf = SubRL->_bf;
	_RotateR(SubR);
	_RotateL(parent);
	if (tmp_bf == 0)
		parent->_bf = SubRL->_bf = 0;
	else if (tmp_bf == -1)
	{
		parent->_bf = 0;
		SubR->_bf = 1;
	}
	else
	{
		parent->_bf = -1;
    	SubR->_bf = 0;
	}
	SubRL->_bf = 0;
}

4.先左单旋再右单旋

void _RotateLR(Node*& parent)
{
	Node* SubL = parent->_left;
	Node* SubLR = SubL->_right;
	int tmp_bf = 0;
	if (SubLR->_left == nullptr && SubLR->_right == nullptr)
		tmp_bf = 0;
	else
		tmp_bf = SubLR->_bf;
	_RotateL(SubL);
	_RotateR(parent);
	if (tmp_bf == 0)
		parent->_bf = SubLR->_bf = 0;
	else if(tmp_bf == -1)
	{
		parent->_bf = 1;
		SubL->_bf = 0;
	}
	else
	{
		parent->_bf = 0;
		SubL->_bf = -1;
	}
	SubLR->_bf = 0;
}

3.Print

搜索二叉树顺序打印是通过中序遍历得到的

void Print()
{
	_Print(_root);
}

private:
void _Print(Node*& cur)
{
	if (cur == nullptr)
		return;
	_Print(cur->_left);
	cout << cur->_kv.first << endl;
	_Print(cur->_right);
}

4.Check

1. 验证其为二叉搜索树

如果中序遍历可得到一个有序的序列,就说明为二叉搜索树

2. 验证其为平衡树

每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)
节点的平衡因子是否计算正确

bool Check()
{
	return _Check(_root, 0);
}

private:
int Height(Node* root)
{
	if (root == nullptr)
		return 0;
	int Left = 1 + Height(root->_left);
	int Right = 1 + Height(root->_right);

	return (Left > Right ? Left : Right);
}

bool _Check(Node* root,int num)
{
	if (root == nullptr)
		return true;

	int leftHeight = Height(root->_left);
	int rightHeight = Height(root->_right);
    int diff = rightHeight - leftHeight;
	if (diff != root->_bf)
	{
		cout << "_bf false";
		return false;
	}
	if (diff < -1 || diff > 1)
	{
		cout << "diff false";
		return false;
	}

	return _Check(root->_left, leftHeight) && _Check(root->_right, rightHeight);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/436950.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Redis】Redis十大数据类型—哈希hash

介绍 Hash 是一个键值对&#xff08;key - value&#xff09;集合&#xff0c;其中 value 的形式入&#xff1a;value[{field1&#xff0c;value1}&#xff0c;...{fieldN&#xff0c;valueN}]。Hash 特别适合用于存储对象。 Hash和String对象的区别 内部实现 Hash 类型的底…

SpringMVC 接收前端传递的参数

SpringMVC 接受前端传参 1、前端传参需要注意请求的Content-type, 主要使用的有两种&#xff1a; application/x-www-form-urlencodedapplication/json application/x-www-form-urlencoded是浏览器的默认编码格式 &#xff0c;对于原生的form 表单提交参数&#xff0c;就是使用…

【大数据之Hadoop】十六、MapReduce之Join

1 Reduce Join Map端&#xff1a; 为来自不同表或文件的key/value对&#xff0c;打标签以区别不同来源的记录。然后用连接字段作为key&#xff0c;其余部分和新加的标志作为value&#xff0c;最后进行输出。 Reduce端&#xff1a; 在每一个分组当中将那些来源于不同文件的记录…

【剑指 offer】调整数组顺序使奇数位于偶数前面

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;算法训练营&#x1f447; 调 整 数 组 顺 序 使 奇 数 位 于 偶 数 前 面 核心考点&#xff1a;数组操作&#xff0c;排序思想的扩展使用 描述&#xff1a; 输入一个整数数组&#xff0c;实现一个函数来调…

vue2数据响应式原理(3) 带你手写一个defineReactive响应式函数并理解其本质

然后 我们来学一下defineReactive函数 defineReactive其实是一个要声明的函数 基本都是作为一个响应式函数 因为vue的使用比较经典 因此 也成了 响应式的一个代表函数 而定义它的意义在于 defineProperty不好用 具体不好用在哪呢&#xff1f; 我们打开上文用到的项目 将output…

第六讲 循环结构

我们在写程序的时候&#xff0c;极有可能遇到需要重复执行某条指令或某些指令的场景&#xff0c;例如我们需要每隔1秒钟在屏幕上输出一次“hello, world”并持续输出一个小时。如下所示的代码可以完成一次这样的操作&#xff0c;如果要持续输出一个小时&#xff0c;我们就需要把…

Javaee spring jdbctemplate查询数据库,基于纯注解实现

为啥要用纯注解方式呢&#xff1f;因为xml中代码还是有点多&#xff0c;纯注解可以解决该问题 现在要做的很简单&#xff0c;就是用新建的SpringConfig这个类去替代xml 在测试类中加载核心配置类 SpringConfig类中 Configuratio Spring.xml配置类 ComponentScan <!--开…

Linux搭建Web服务器(三)——服务器编程基本框架以及事件处理模式

目录 0x01 服务器编程基本框架 0x02 两种高效的事件处理模式 Reactor 模式 Proactor 模式 模拟Proactor 模式 0x01 服务器编程基本框架 虽然服务器程序的种类繁多&#xff0c;但是其基本框架都是一样的&#xff0c;不同之处是在于处理逻辑。对于我们在这个服务器的搭建可以…

基于Jenkins实现Docker应用的持续集成与部署

先决条件 1. 服务器部署安装有docker 在docker应用开发中最常见的就是开发Dockerfile文件&#xff0c;可以使用代码仓库来管理它。 而在企业私有开发环境中是无法访问公有代码仓库&#xff08;如Github&#xff09;的。这时可以搭建私有代码仓库。 部署安装svn私有仓库 安…

GPT-4 验明真身的三个经典问题:快速区分 GPT-3.5 与 GPT-4

现在已经有很多 ChatGPT 的套壳网站&#xff0c;以下分享验明 GPT-4 真身的三个经典问题&#xff0c;帮助你快速区分套壳网站背后到底用的是 GPT-3.5 还是 GPT-4。 测试问题 1&#xff1a;What is tomorrow in relation to yesterday’s today&#xff1f;&#xff08;昨天的当…

《Shunted Transformer: Shunted Self-Attention》CVPR 2022 oral

论文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2022/papers/Ren_Shunted_Self-Attention_via_Multi-Scale_Token_Aggregation_CVPR_2022_paper.pdf 代码链接&#xff1a;https://github.com/OliverRensu/Shunted-Transformer​ 1. 动机 视觉转换器(ViT)模型…

vscode怎么对选定的代码格式化?ctrl+k,ctrl+f(格式化代码)

先选中代码&#xff1a; 然后按CTRL K 再按CTRLF 也可以先选择要格式化的代码块&#xff0c;ctrlshiftp&#xff0c;搜索format&#xff0c;然后第二个就是&#xff1a;

助你掌握搜索神器,10个实用的Elasticsearch查询技巧

前言 Elasticsearch是一个非常流行的搜索引擎&#xff0c;已经成为了许多企业的首选解决方案。然而&#xff0c;我们要想成为一个优秀的程序员&#xff0c;就必须掌握各种查询技巧。本文将向大家介绍10个实用的Elasticsearch查询技巧&#xff0c;并配上详细的代码示例&#xff…

Python基础实战1-简单介绍python

1 Python介绍 Python是一门优雅而健壮的编程语言&#xff0c;它继承了传统编程语言的强大性和通用性&#xff0c;同时也借鉴了脚本语言和解释语言的易用性。 1.1 Python的历史 Python是由创始人贵铎范罗萨姆&#xff08;Guido van Rossum&#xff09;在阿姆斯特丹于1989年圣…

在数字化质变“奇点”时刻,看数字生产力跃升的华为观

&#xff08;华为轮值董事长孟晚舟&#xff09; 进入2023年&#xff0c;以大语言模型为代表的新AI&#xff0c;打开了全球对于数字生产力的全新认知&#xff1a;高盛集团经济学家认为&#xff0c;ChatGPT等生成式AI最终可能在10年的时间里使得全球年GDP增长7%&#xff08;近7万…

pinia持久化存储方案——pinia-storage(自己写的,持续更新)

pinia持久化存储方案——pinia-storage pinia-storagepinia-storage Introduction版本更新说明(update introduction)安装(install)npm 安装&#xff08;npm install&#xff09; QuickStartcreate piniastore/indexstore/indexPinia.tsstore/indexPinia.js main.ts | main.jsA…

Direct3D 12——几何着色器——几何着色器概念

几何着色器 几何着色器这个可选阶段便位于顶点着色器与像素着色器之间。几何着色器所输出的图元由顶点列表定义而成。在退岀几何着色器时&#xff0c;必将顶点的位置变换到齐次 裁剪空间。换言之&#xff0c;经过几何着色器阶段的处理后&#xff0c;我们就得到了位于齐次裁剪空…

MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点3:EXPLAIN ANALYZE

文章目录 MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点3&#xff1a;EXPLAIN ANALYZEEXPLAIN ANALYZE介绍EXPLAIN ANALYZE的特性EXPLAIN 和EXPLAIN ANALYZE的结果对比例题例题解析参考 MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点3&#xff1a;EXPLAIN ANALYZE EXPLAIN…

部门来了个测试人,听说是00后,上来一顿操作给我看呆了...

今天上班开早会就是新人见面仪式&#xff0c;听说来了个很厉害的大佬&#xff0c;年纪还不大&#xff0c;是上家公司离职过来的&#xff0c;薪资已经达到中高等水平&#xff0c;很多人都好奇不已&#xff0c;能拿到这个薪资应该人不简单&#xff0c;果然&#xff0c;自我介绍的…

网络原理(TCP/UDP)

目录 一. 网络基础 1. IP地址 2. 端口号 3. 协议 4. OSI七层模型 二. UDP协议 2.1 UDP的协议端格式&#xff1a; 2.2 UDP的特点 三. TCP协议 3.1 TCP协议段格式 3.2 TCP原理 &#xff08;1&#xff09;确认应答机制 &#xff08;2&#xff09;超时重传机制 &#xff…