C++进阶——AVL树的构建

news2024/10/7 2:28:14

C++进阶——AVL树的构建

AVL树

概念

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

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
在这里插入图片描述

如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在O(logN),搜索时
间复杂度O(logN)。

AVL树节点的定义

template<class K,class V>
	struct AVLTreeNode
	{
		AVLTreeNode(const pair<k,v>& kv)//节点构造函数
			:_left(nullptr)
			,_right(nullptr)
			,_parent(nullptr)
			,_kv(kv)
			,_be(0)
		{

		}

		AVLTreeNode<K, V>* _left;
		AVLTreeNode<K, V>* _right;
		AVLTreeNode<K, V>* _parent;
		pair<k, v> _kv;
		int _be;//balance element
	};

AVL树节点的插入

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么AVL树的插入
过程可以分为两步:

  1. 按照二叉搜索树的方式插入新节点
  2. 调整节点的平衡因子

那如果满足不了平衡因子该怎么办呢?
没错,就是旋转、跳跃、我不停歇
右右——单左旋
在这里插入图片描述

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

			parent->_right = subRL;
			if(subRL)
				subRL->parent = parent;

			node* ppnode = parent->_parent;
			subR->_left = parent;
			parent->_parent = subR;

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

			parent->_be = subR->_be = 0;
		}

左左——单右旋

在这里插入图片描述

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

			subL->_left = subLR;
			
			if (subLR)
				subLR->_parent=parent;

			node* ppnode = parent->_parent;
			subL->_right = parent;
			parent->_parent = subL;
			if (parent == _root)
			{
				_root = subL;
				_root->_parent = nullptr;
			}
			else
			{
				if (ppnode->_left == parent)
				{
					ppnode->_left = subL;
				}
				else
				{
					ppnode->_right=subL;
				}
				subL->_parent = ppnode;
			}
			subL->_be = parent->_be = 0;
		}

新节点插入较高左子树的右侧—左右:先左单旋再右单旋
在这里插入图片描述

void RotateLR(node* parent)
		{
			node* subL = parent->_left;
			node* subLR = subL->_right;
			int be = subLR->_be;

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

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

新节点插入较高右子树的左侧—右左:先右单旋再左单旋
在这里插入图片描述

void RotateRL(node* parent)
		{
			node* subR = parent->_right;
			node* subRL = subR->_left;
			int be = subRL->_be;
			RotateR(parent->_right);
			RotateL(parent);
			if (be == 1)
			{
				parent->_be = 0;
				subRL->_be = 0;
				subR->_bf = -1;
			}
			else if (be == -1)
			{
				parent->_be = 1;
				subRL->_be = 0;
				subR->_be = 0;
			}
			else if (be == 0)
			{
				parent->_be = 0;
				subRL->_be = 0;
				subR->_be = 0;
			}
			else
			{
				assert(false);
			}
		}

总结:
假如以pParent为根的子树不平衡,即pParent的平衡因子为2或者-2,分以下情况考虑

  1. pParent的平衡因子为2,说明pParent的右子树高,设pParent的右子树的根为pSubR
    当pSubR的平衡因子为1时,执行左单旋
    当pSubR的平衡因子为-1时,执行右左双旋
  2. pParent的平衡因子为-2,说明pParent的左子树高,设pParent的左子树的根为pSubL
    当pSubL的平衡因子为-1是,执行右单旋
    当pSubL的平衡因子为1时,执行左右双旋
    旋转完成后,原pParent为根的子树个高度降低,已经平衡,不需要再向上更新。

判断是否是平衡树

一下函数可以判断是否是平衡树,还有计算树的高度。

int _Height(node* pRoot)
		{
			if (pRoot == nullptr)
				return 0;
			int leftHight = _Height(pRoot->_left);
			int rightHight = _Height(pRoot->_right);

			return leftHight > rightHight ? leftHight + 1:rightHight + 1;
		}
		bool _IsBalanceTree(node* pRoot)
		{
			// 空树也是AVL树
			if (nullptr == pRoot) return true;
			// 计算pRoot节点的平衡因子:即pRoot左右子树的高度差
			int leftHeight = _Height(pRoot->_pLeft);
			int rightHeight = _Height(pRoot->_pRight);
			int diff = rightHeight - leftHeight;
			// 如果计算出的平衡因子与pRoot的平衡因子不相等,或者
			// pRoot平衡因子的绝对值超过1,则一定不是AVL树
			if (diff != pRoot->_bf || (diff > 1 || diff < -1))
				return false;
			// pRoot的左和右如果都是AVL树,则该树一定是AVL树
			return _IsBalanceTree(pRoot->_pLeft) && _IsBalanceTree(pRoot->_pRight);
		}

AVL树的性能

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证
查询时高效的时间复杂度,即。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:
插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。
因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,
但一个结构经常修改,就不太适合。

整体的代码:

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

namespace tom 
{
	template<class K,class V>
	struct AVLTreeNode
	{
		AVLTreeNode(const pair<K,V>& kv)//节点构造函数
			:_left(nullptr)
			,_right(nullptr)
			,_parent(nullptr)
			,_kv(kv)
			,_be(0)
		{

		}

		AVLTreeNode<K, V>* _left;
		AVLTreeNode<K, V>* _right;
		AVLTreeNode<K, V>* _parent;
		pair<K, V> _kv;
		int _be;//balance element
	};

	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* cur = _root;
			node* parent = nullptr;
			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->_right)
				{
					parent->_be++;
				}
				else
				{
					parent->_be--;
				}

				if (parent->_be == 1 || parent->_be == -1)
				{
					parent = parent->_parent;
					cur = cur->_parent;
				}
				else if (parent->_be == 0)
				{
					break;
				}
				else if (parent->_be == 2 || parent->_be == -2)
				{
					if (parent->_be == -2 && cur-> - 1)
					{
						RotateR(parent);
					}
					else if (parent->_be == 2 && cur-> 1)
					{
						RotateL(parent);
					}
					else if (parent->_be == 2 && cur-> - 1)
					{
						RotateRL(parent);
					}
					else if (parent->_be == -2 && cur-> 1)
					{
						RotateLR(parent);
					}
					else
					{
						assert(false);
					}
				}
			}
		}
	private:
		void RotateL(node* parent)
		{
			node* subR = parent->_right;
			node* subRL = subR->_left;

			parent->_right = subRL;
			if(subRL)
				subRL->parent = parent;

			node* ppnode = parent->_parent;
			subR->_left = parent;
			parent->_parent = subR;

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

			parent->_be = subR->_be = 0;
		}
		void RotateR(node* parent)
		{
			node* subL = parent->_left;
			node* subLR = subL->_right;

			subL->_left = subLR;
			
			if (subLR)
				subLR->_parent=parent;

			node* ppnode = parent->_parent;
			subL->_right = parent;
			parent->_parent = subL;
			if (parent == _root)
			{
				_root = subL;
				_root->_parent = nullptr;
			}
			else
			{
				if (ppnode->_left == parent)
				{
					ppnode->_left = subL;
				}
				else
				{
					ppnode->_right=subL;
				}
				subL->_parent = ppnode;
			}
			subL->_be = parent->_be = 0;
		}
		void RotateRL(node* parent)
		{
			node* subR = parent->_right;
			node* subRL = subR->_left;
			int be = subRL->_be;
			RotateR(parent->_right);
			RotateL(parent);
			if (be == 1)
			{
				parent->_be = 0;
				subRL->_be = 0;
				subR->_bf = -1;
			}
			else if (be == -1)
			{
				parent->_be = 1;
				subRL->_be = 0;
				subR->_be = 0;
			}
			else if (be == 0)
			{
				parent->_be = 0;
				subRL->_be = 0;
				subR->_be = 0;
			}
			else
			{
				assert(false);
			}
		}
		void RotateLR(node* parent)
		{
			node* subL = parent->_left;
			node* subLR = subL->_right;
			int be = subLR->_be;

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

			if (be == 1)
			{
				parent->_be = 0;
				subLR->_be = 0;
				subL->_bf = -1;
			}
			else if (be == -1)
			{
				parent->_be = 1;
				subLR->_be = 0;
				subL->_be = 0;
			}
			else if (be == 0)
			{
				parent->_be = 0;
				subLR->_be = 0;
				subL->_be = 0;
			}
			else
			{
				assert(false);
			}
		}
	private:
		node* _root = nullptr;

	};
}

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

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

相关文章

2023Python最火的第三方开源测试框架 ——pytest

一、介绍 本篇文章是介绍的是Python 世界中最火的第三方单元测试框架&#xff1a;pytest。 它有如下主要特性&#xff1a; assert 断言失败时输出详细信息&#xff08;再也不用去记忆 self.assert* 名称了&#xff09;自动发现测试模块和函数模块化夹具用以管理各类测试资源对…

顺序表,让数据有序飞舞:C语言实现全攻略

本篇博客会讲解顺序表这种数据结构的相关知识&#xff0c;并且使用C语言实现一个顺序表。 概述 什么是顺序表呢&#xff1f;顺序表是一种线性的数据结构&#xff0c;其特点是&#xff1a;数据是从第一个位置开始&#xff0c;连续存放的。其实&#xff0c;你完全可以把它等价于…

哈工大软件过程与工具作业3

哈尔滨工业大学 计算学部/软件学院 2022年秋季学期 2020级本科《软件过程与工具》课程&#xff08;3.0学分&#xff09; 作业报告 作业3&#xff1a;软件测试报告 姓名 学号 联系方式 石卓凡 120L021011 944613709qq.com/18974330318 目 录 1 作业目的与要求...........…

《计算机网络—自顶向下方法》 Wireshark实验(七):以太网与ARP协议分析

1 以太网 1.1 介绍 以太网是现实世界中最普遍的一种计算机网络。以太网有两类&#xff1a;第一类是经典以太网&#xff0c;第二类是交换式以太网&#xff0c;使用了一种称为交换机的设备连接不同的计算机。 经典以太网&#xff1a;是以太网的原始形式&#xff0c;运行速度从 …

股价与期待值“背道而驰”,友车科技能否站稳科创板?

上周&#xff0c;共计7只新股登陆A股&#xff0c;其中&#xff0c;用友汽车信息科技&#xff08;上海&#xff09;股份有限公司&#xff08;以下简称友车科技&#xff09;于5月11日在科创板上市。发行价为33.99元&#xff0c;发行3607.94万股&#xff0c;募资总额为12.24亿元。…

jmeter接口测试项目实战详解,零基础也能学,源码框架都给你

目录 1.什么是jmeter&#xff1f; 2.jmeter能做什么&#xff1f; 3.jmeter环境搭建 3.1前提&#xff1a; 3.2jmeter下载&#xff1a; 3.3jmeter环境搭建&#xff1a; 3.3.1mac当中jmeter环境搭建&#xff1a; 3.4jmeter基本配置 3.4.1.切换语言 3.4.2.安装插件 4.jmet…

MySQL数据库基础2

文章目录 数据类型表的约束 数据类型 1、数值类型&#xff1a;BIT、TINYINT、BOOL、SMALLINT、INT、BIGINT、FLOAT[(M,D)]、DOUBLE[(M,D)]、DECIMAL[(M,D)] FLOAT[(M,D)]&#xff1a;占用四个字节&#xff0c;M表示显示位数&#xff0c;D表示小数位数&#xff0c;精度保证&am…

5年测试,已失业3个月.....

我做测试5年&#xff0c;一线城市薪水拿到15K&#xff0c;中间还修了一个专升本&#xff0c;这个年限不说资深肯定也是配得上经验丰富的。今年行情不好人尽皆知&#xff0c;但我还是对我的薪水不是很满意&#xff0c;于是打算出去面试&#xff0c;希望可以搏一个高薪。 但真到面…

测试自动化工具_Katalon

测试自动化_Katalon 1.概述 ​ Katalon界面的自动化测试工具&#xff0c;简称KS&#xff0c;于2015年推出。是开源的&#xff0c;提供的版本有免费的版本&#xff0c;还有企业版是收费的。如下图。其中的服务台功能应该是持续继承的支持。可试用一个月。 ​ 最初是支持Web UI…

Chatgpt论文笔记——MiNiGPT4解读

前言 代码地址&#xff1a;https://github.com/Vision-CAIR/MiniGPT-4 摘要 摘要写的就很简单了&#xff0c;标黄的是重点&#xff0c;可以看到这个方法很简单&#xff0c;就是拿了一个视觉的encoder&#xff08;Blip-2&#xff09;以及拿了一个文本的encoder&#xff08;Vic…

OpenPCDet系列 | 5.2 PointPillars算法——PointPillarScatter伪图像BEV特征构建模块

文章目录 PointPillarScatter模块1. PointPillarScatter初始化2. PointPillarScatter前向传播 OpenPCDet的整个结构图&#xff1a; PointPillarScatter模块 在进行了PillarVFE编码后&#xff0c;此时的batch_dict更新如下所示&#xff0c;追加了pillar_features字段&#xf…

好程序员:转行学Java怎么样?什么工作可以月入过万?

去年的时候有个学妹跟小源说&#xff0c;想转行&#xff0c;但是目前又比较迷茫&#xff0c;不知道该从事啥行业&#xff1f;她跟小源说了下具体情况&#xff0c;本科学历&#xff0c;Java零基础。小源让好程序员的就业老师跟她分享了下相关的it行业规划&#xff0c;最后她学了…

Python实现ACO蚁群优化算法优化循环神经网络分类模型(LSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蚁群优化算法(Ant Colony Optimization, ACO)是一种源于大自然生物世界的新的仿生进化算法&#xff0c…

关于摄影艺术欣赏分享(私密空间+玛丽娜·阿布拉莫维奇+世界十大最昂贵的摄影作品欣赏+《死亡路上的对话》+马良作品)

文章的内容灵感是旁听课而来的呀&#xff0c;搜了很多相关文章很喜欢 1. 出去遛狗&#xff0c;晚点回来 国外文化中国文化&#xff08;国外不可以随意拍摄照片&#xff09; 公共空间私密空间 艺术的价值在于可以给人们思考&#xff0c;颠覆常识 2. 行为艺术之母玛丽娜阿布拉…

YOLOv5【目录结构源码】超详细注释解读!!!建议收藏✨✨!

上一篇文章介绍了YOLOv5的网络的详细解读&#xff1a;直通车&#x1f680; 由于以后的学习及在进行的项目打算YOLOv5再仔细研究进行使用及改进&#xff0c;接下来会出相关于YOLOv5的代码逐行解读以及注释&#xff0c;废话不多说&#xff0c;让我们一起学习YOLOv5源码吧&#xf…

CTFshow pwn03

题目&#xff1a; 在做本道题前&#xff0c;我们先了解所必要的知识 Libc是什么&#xff1f; 英文名字&#xff1a;Standard C library&#xff0c;其翻译过来&#xff0c;C语言标准库 它是符合ANSI C标准的一个函数库 学过C语言会明白 ANSI C标准又是什么&#xff1f; 198…

Redo log

目录标题 前言为什么需要redo log redo log中的WAL&#xff08;先写日志&#xff0c;再写磁盘&#xff09;重要参数innodb_flush_log_at_trx_commit如何选择 redo log记录形式日志块(log block)redo log的格式 redo log何时刷入磁盘正常关闭服务器时事务提交时&#xff08;inno…

【STL】string的使用

放在专栏【C知识总结】&#xff0c;会持续更新&#xff0c;期待支持&#x1f339; STL简介 STL的诞生 STL为英文Standard Template Library的缩写&#xff0c;译为标准模板库。是C标准库的重要组成部分。 长久以来&#xff0c;软件届一直希望建立一种可重复运用的东西。所谓…

首个支持RWA交易的订单簿DEX-PoseiSwap,即将开启IEO

随着 DeFi 世界的发展&#xff0c;越来越多的链上协议支持以合成资产的方式&#xff0c;将传统金融资产以加密资产的形式映射至链上&#xff0c;包括美股、黄金期货等等&#xff0c;虽然这种方式进一步帮助投资者&#xff0c;以非许可的形式丰富了投资标的&#xff0c;但这种方…

GraphPad Prism 9.5.1 for Mac 操作简便功能强大且实用的医学绘图分析工具

GraphPad Prism简介 GraphPad Prism是一款非常实用的统计软件&#xff0c;其功能非常强大&#xff0c;能够帮助用户进行各类科研数据的处理和分析&#xff0c;快速绘制出各种专业的图像和数据报告。 GraphPad Prism软件的用户界面非常友好&#xff0c;易于学习和操作&#xf…