C++: AVL树的实现

一.AVL树的旋转

AVL树是平衡搜索二叉树的一种。

平衡因子:节点右树的高度减左树的高度,AVL树规定平衡因子的绝对值小于2。若不在这个范围内,说明该树不平衡。

AVL树节点:

struct AVLTreeNode
{AVLTreeNode(const T& data = T()): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _bf(0){}AVLTreeNode<T>* _pLeft;AVLTreeNode<T>* _pRight;AVLTreeNode<T>* _pParent;T _data;int _bf;   // 节点的平衡因子
};

如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构, 使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:

1. 新节点插入较高左子树的左侧---左左:右单旋

void RotateL(Node* pParent){Node* SubR = pParent->_pRight; Node* SubRL = SubR->_pLeft;pParent->_pRight = SubRL;if (SubRL)SubRL->_pParent = pParent;SubR->_pLeft = pParent;pParent->_pParent = SubR;if (pParent->_pParent == nullptr){_pRoot = SubR;SubR->_pParent = nullptr;}else{if (pParent->_pParent->_pLeft == pParent){pParent->_pParent->_pLeft = SubR;}else{pParent->_pParent->_pRight = SubR;}}SubR->_bf = SubRL->_bf = 0;}

2. 新节点插入较高右子树的右侧---右右:左单旋

void RotateR(Node* pParent){Node* SubL = pParent->_pLeft;Node* SubLR = SubL->_pRight;pParent->_pLeft = SubLR;if(SubLR)SubLR->_pParent = pParent;SubL->_pRight = pParent;pParent->_pParent = SubL;if (pParent->_pParent == nullptr){_pRoot = SubL;SubL->_pParent = nullptr;}else{if (pParent == pParent->_pParent->_pRight){pParent->_pParent->_pRight = SubL;}else{pParent->_pParent->_pLeft = SubL;}SubL->_pParent = pParent->_pParent;}SubL->_bf = SubLR->_bf = 0;}

3. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋

void RotateLR(Node* pParent){Node* SubL = pParent->_pLeft;Node* SubLR = SubL->_pRight;RotateL(SubL);RotateR(pParent);if (SubLR->_bf == -1){SubL->_bf = 0;SubLR->_bf = 0;pParent->_bf = 1;}else if (SubLR->_bf == 1){SubL->_bf = -1;SubLR->_bf = 0;pParent->_bf = 0;}else{assert(false);}}

 4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

void RotateRL(Node* pParent){Node* SubR = pParent->_pRight;Node* SubRL = SubR->_pLeft;RotateR(SubR);RotateL(pParent);if (SubRL->_bf == 1){SubR->_bf = 0;pParent->_bf = -1;SubRL = 0;}else if(SubRL->_bf == 0){SubR->_bf = 0;pParent->_bf = 0;SubRL = 0;}else if (SubRL->_bf == -1){SubR->_bf = 1;pParent->_bf = 0;SubRL = 0;}else{assert(false);}}

 二.AVL树的插入

插入一个节点后平衡因子可能会改变。所以不仅要改变指针方向,还要更新平衡因子的值。

bool Insert(const T& data){if (_pRoot == nullptr){_pRoot = new Node(data);return true;}Node* cur = _pRoot;Node* parent = _pRoot;while (cur){if (data < cur->_data){parent = cur;cur = cur->_pLeft;}else if (data < cur->_data){parent = cur;cur = cur->_pRight;}else{return false;}}cur = new Node(data);if (data < parent->_data){parent->_pLeft = cur;}else{parent->_pRight = cur;}//更新平衡因子while (parent){if (parent->_pLeft = cur){parent->_bf-- ;}else{parent->_bf++;}if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_pParent;}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == 2 && cur->_bf == 1){RotateR(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateL(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else{RotateLR(parent);}}else{assert(false);}}return true;}

 三.AVL树的验证

1.求树的高度

size_t _Height(Node* pRoot){if (pRoot == nullptr){return 0;}int LestTreeHeight = _Height(pRoot->_pLeft);int RightTreeHeight = _Height(pRoot->_pRight);return LestTreeHeight > RightTreeHeight ? LestTreeHeight + 1 : RightTreeHeight + 1;}

2.验证是否为平衡二叉树

bool _IsAVLTree(Node* pRoot){if (pRoot == nullptr){return true;}int LestTreeHeight = _Height(pRoot->_pLeft);int RightTreeHeight = _Height(pRoot->_pRight);int diff = RightTreeHeight - LestTreeHeight;if (abs(diff) >= 2 || abs(diff) != pRoot->_bf){return false;}return _IsAVLTree(pRoot->_pLeft) && _IsAVLTree(pRoot->_pRight);}

3.测试用例验证

int main()
{int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16,14 };AVLTree<int> a;for (int i = 0; i < sizeof(arr) / sizeof(arr[0]);i++){a.Insert(i);}cout << a.IsAVLTree() << endl;return 0;
}

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

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

相关文章

数据结构--堆的深度解析

目录 引言 一、基本概念 1.1堆的概念 1.2堆的存储结构 1.3堆的特点 二、 堆的基本操作 2.1初始化 2.2创建堆 2.3插入元素 2.4删除元素 2.5堆化操作 2.6堆的判空 2.7获取堆顶元素 三、堆的常见应用 1. 优先队列 2. 堆排序 3. Top-k 问题 4. 图论中的应用 四…

rom定制系列------小米5x_miui12安卓11定制固件界面预览 小米5x第三方固件

&#x1f49d;&#x1f49d;&#x1f49d;此固件来源于客户卡刷固件定制。客户需要修改为线刷。并且修改账号锁功能。 可以让客户使用官方平台批量进行刷写。方便操作。 定制机型以及功能预览&#x1f49d;&#x1f49d;&#x1f49d; 小米5x版本miui12.5.8安卓11固件。此机型…

中国网络隐私保护:机遇与挑战并存的未来

随着数字经济的蓬勃发展&#xff0c;中国已进入大数据和互联网高速发展的时代。伴随而来的&#xff0c;是公众对网络隐私保护的强烈需求。从电子支付到社交平台&#xff0c;从智能家居到人脸识别&#xff0c;网络数据正在全面渗透到人们生活的方方面面。然而&#xff0c;数据隐…

MySQL 连接

使用MySQL二进制方式连接 使用MySQL二进制方式进入到MySQL命令提示符下来连接MySQL数据库。 实例 以下是从命令行中连接MySQL服务器的简单实例&#xff1a; [roothost]# mysql -u root -p Enter password:******在登录成功后会出现 mysql> 命令提示窗口&#xff0c;你可以在…

建造者模式(C++)

定义&#xff1a;建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它主要用于构建一个复杂对象&#xff0c;并将其构建过程与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。该模式通过将复杂对象的构建过程分解为多个简单的步…

安装雷池社区版,保护网站安全

环境依赖 安装雷池前请确保你的系统环境符合以下要求 操作系统&#xff1a;LinuxCPU 指令架构&#xff1a;x86_64CPU 指令架构&#xff1a;支持 ssse3 指令集软件依赖&#xff1a;Docker 20.10.14 版本以上软件依赖&#xff1a;Docker Compose 2.0.0 版本以上最低资源需求&am…

Linux NFS 服务器 搭建

1、安装 NFS 确保Linux联网 sudo apt-get install nfs-kernel-server 2、创建一个目录&#xff0c;并在该文件下创建一个文件&#xff0c;用于测试nfs。 sudo mkdir /nfssudo mkdir /nfs/rootfscd /nfs/rootfs/sudo vim test.txt在里面随便加点内容 esc :wq 保存退出就可以了 …

Java 文件拷贝

1.小文件拷贝 实例代码&#xff1a; 上面程序运行的图示&#xff1a; 弊端&#xff1a;一次读一个字节&#xff0c;效率太慢。所以需要一次读取多个字节。 2.大文件拷贝 结果&#xff1a;

云原生开发 - 监控(简约版)

要在程序中暴露指标&#xff0c;并符合 Prometheus 和 Kubernetes 的规范&#xff0c;可以按照以下步骤进行&#xff1a; 1. 选择合适的库 根据你的编程语言选择适合的 Prometheus 客户端库。例如&#xff1a; Go: github.com/prometheus/client_golangJava: io.prometheus:…

UE5运行时动态加载场景角色动画任意搭配-全流程代码(四)

UE5运行时动态加载场景、角色、角色动画、相机动画任意搭配,Android、iOS也可以跑,横竖屏兼容,手机竖屏: 1、场景切换UWorld处理 在通过OpenLevel进行场景切换的时候,UWorld会发生变化,需要我们获取正确的UWorld。 1、在GameInstance监听Level加载 void UMyGameInsta…

数据结构——复杂度

目录 数据结构前言 数据结构 算法 算法效率 时间复杂度 大O的渐进表示法 示例1 示例2 示例3 示例4 示例5 示例6 示例7 空间复杂度 示例1 示例2 示例3 示例4 常见复杂度对比 旋转数组 优化1 优化2 这一篇文章我们就开始数据结构知识的学习&#xff01; 数据…

stm32单片机个人学习笔记10(TIM编码器接口)

前言 本篇文章属于stm32单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 STM32入门教程-2023版 细…

Jetpack-Room

Room是Android Jetpack中的一个组件&#xff0c;它提供了一个抽象层&#xff0c;帮助开发者在本地数据库&#xff08;如SQLite&#xff09;上进行持久化数据存储。Room通过简化数据库操作&#xff0c;使得数据管理变得更加容易和高效。 Room重要的概念 实体&#xff08;Entit…

R知识图谱1—tidyverse玩转数据处理120题

以下是本人依据张老师提供的tidyverse题库自行刷题后的tidyverse Rmd文件&#xff0c;部分解法参考张老师提示&#xff0c;部分解法我本人灵感提供 数据下载来源https://github.com/zhjx19/tidyverse120/tree/main/data 参考https://github.com/MaybeBio/R_cheatsheet/tree/mai…

Python即时获取上证指数信息并发送邮件到指定邮箱

最近股市振荡&#xff0c;股民会时不时查看一下上证指数信息&#xff0c;但是繁忙的工作却时不是让人忘记了&#xff0c;错过了投资的最佳时机&#xff0c;这时就可以通过Python来爬取网站上的上证指数&#xff0c;并发送到指定的邮箱&#xff0c;这样就不用上指定网页也以获取…

2024最新分别利用sklearn和Numpy实现c均值对鸢尾花数据集进行聚类(附完整代码和注释)

C均值聚类算法&#xff08;K-Means Clustering&#xff09;是一种非常流行的聚类算法&#xff0c;用于将数据点分成多个簇&#xff0c;使得簇内的点尽可能相似&#xff0c;簇间的点尽可能不同。以下是K-Means算法的基本步骤&#xff1a; 1. 初始化&#xff1a;随机选择K个点作…

网络断开导致SSH会话和服务端任务终止的原因及使用screen详解

在进行深度学习任务时&#xff0c;常常在本地通过ssh连接远程服务器进行炼丹任务。当我在pycharm上远程连接到服务器上进行训练时&#xff0c;由于网络不稳定使得SSH断开连接&#xff0c;我原以为服务器不会受影响。通过nvidia-smi命令发现GPU占用为0&#xff0c;这才发现任务终…

稀土阻燃协效剂 - 阻燃

金士镧稀土阻燃协效剂的技术衬垫&#xff1a; 金士镧KingCela 稀土阻燃协效剂KCL-FR-06xx系列产品&#xff0c;凭借独特的稀土4f电子层结构, 可协效磷氮阻燃剂&#xff0c;卤系阻燃剂阻燃剂在高分子材料&#xff08;橡胶&#xff0c;塑料&#xff0c;涂层&#xff0c;胶黏剂&a…

『网络游戏』服务器启动逻辑【16】

新建Visual Studio工程命名为NetGameServer 重命名为ServerStart.cs 创建脚本&#xff1a; 编写脚本&#xff1a;ServerRoot.cs 编写脚本&#xff1a;ServerStart.cs 新建文件夹 调整脚本位置 新建文件夹 新建文件夹网络服务 创建脚本&#xff1a;NetSvc.cs 编写脚本&#xff1…

使用 KVM 在 Xubuntu 上创建 Windows 10 虚拟机

目录 前言说明注意准备 iso官网思博主(嘻嘻)拖动到虚拟机里面启动 virt-manager创建虚拟机选择本地安装介质选择 iso配置 内存 和 CPU选择 创建的虚拟机 保存的位置启动虚拟机看到熟悉的 Win10界面前言 XUbuntu安装OpenSSH远程连接服务器 远程连接之MobaXterm安装使用 虚拟化技…