【C++】AVL树

AVL树

  • 1. AVL树的概念
  • 2. AVL树的实现
    • 2.1 节点的定义
    • 2.2 插入
    • 2.3 是否是AVL树
  • 3. AVL树与红黑树


1. AVL树的概念

AVL树是一棵二叉搜索树,但它的每个节点的左右子树的高度差的绝对值不超过1,且它的子树也是平衡二叉树。左右子树的高度差也叫平衡因子,平衡因子 = 右子树叶的高度 - 左子树的高度。

在这里插入图片描述
将AVL树与满二叉树对比,看看AVL的效率如何?
在这里插入图片描述


2. AVL树的实现

2.1 节点的定义

//节点
template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _bf;//平衡因子AVLTreeNode(const pair<K, V> kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){}
};

2.2 插入

  1. AVL树是二叉搜索树,所以首先按照二叉搜索树的规矩插入。插入后再考虑插入节点后,AVL树是否平衡。
  2. 有个例子

(1)更新后parent的平衡因子如果是1或者-1,说明parent所在子树的高度发生变化,会影响祖先,需要沿着到root的路径往上更新。
在这里插入图片描述

(2)更新后parent的平衡因子如果是0,说明parent所在子树的高度不变,不用继续沿着到root的路径往上更新。
在这里插入图片描述

(3)更新后parent的平衡因子如果是2或者-2,说明parent所在子树的高度变化且不平衡,对parent的子树进行旋转,使其平衡。
在这里插入图片描述
(4)如果parent是头节点,对parent进行旋转后,记得更新根节点。

  1. 旋转的原理

节点的插入可以分为以下几种情况
(1)左单旋:新节点插入在较高右子树的右侧
在这里插入图片描述
(2)右单旋:新节点插入较高左子树的左侧
在这里插入图片描述

(3)双旋:新节点插入较高右子树的左侧
在这里插入图片描述

(4)双旋:新节点插入较高左子树的右侧
在这里插入图片描述
代码

template<class K, class V>
class AVLTree
{
public:typedef AVLTreeNode<K, V> Node;bool insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* cur = _root;Node* parent = cur;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 < cur->_kv.first){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}//更新平衡因子while (parent){if (parent->_left == cur){--parent->_bf;}else{++parent->_bf;}//如果更新完平衡因子为0,说明其左右子树等高,已经平衡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){//新节点插入较高右子树的右侧,需要将parent左旋if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}//新节点插入较高左子树的左侧,需要将parent右旋else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}//新节点插入较高右子树的左侧,需要先将cur右旋,再将parent左旋else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}//新节点插入较高左子树的右侧,需要先将cur左旋,再将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* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;if (curleft){curleft->_parent = parent;}cur->_left = parent;//不要忘记父节点的链接Node* pparent = parent->_parent;parent->_parent = cur;//要考虑parent的parent是否存在if (pparent){if (pparent->_left == parent){pparent->_left = cur;}else{pparent->_right = cur;}cur->_parent = pparent;}else{_root = cur;cur->_parent = nullptr;}//平衡因子置为0parent->_bf = cur->_bf = 0;}//右旋void RotateR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if (curright){curright->_parent = parent;}cur->_right = parent;Node* pparent = parent->_parent;parent->_parent = cur;if (pparent){if (pparent->_left == parent){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = pparent;}else{_root = cur;cur->_parent = nullptr;}parent->_bf = cur->_bf = 0;}//双旋:新节点插入较高右子树的左侧void RotateRL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;//先右旋,再左旋RotateR(cur);RotateL(parent);if (curleft->_bf == 0){parent->_bf = 0;cur->_bf = 0;}else if (curleft->_bf == 1){parent->_bf = -1;cur->_bf = 0;}else if (curleft->_bf == -1){parent->_bf = 0;cur->_bf = 1;}}//双旋:新节点插入较高左子树的右侧void RotateLR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;//先左旋再右旋RotateL(cur);RotateR(parent);//更新平衡因子if (curright->_bf == 0){parent->_bf = 0;cur->_bf = 0;}else if (curright->_bf == 1){parent->_bf = 0;cur->_bf = -1;}else if (curright->_bf == -1){parent->_bf = 1;cur->_bf = 0;}}
private:Node* _root = nullptr;
};

2.3 是否是AVL树

如果一棵AVL树不平衡,那么它的左右子树的高度差的绝对值超过2,旋转出现问题。如果要判断一棵树是否是AVL树是否平衡,不能通过平衡因子判断,因为旋转出现问题,那么平衡因子也会出现问题,所以只能通过高度来判断。
代码

// 根据AVL树的概念验证pRoot是否为有效的AVL树bool IsAVLTree(){return IsAVLTree(_root);}bool IsAVLTree(Node* pRoot){//不能依赖平衡因子,容易监守自盗。如果旋转出现问题,平衡因子也会有问题//所以直接通过高度来判断if (pRoot == nullptr){return true;}int leftHeight = Height(pRoot->_left);int rightHeight = Height(pRoot->_right);//abs返回参数的绝对值return abs(leftHeight - rightHeight) < 2&& IsAVLTree(pRoot->_left) && IsAVLTree(pRoot->_right);}int Height(){return Height(_root);}int Height(Node* root){if (root == nullptr){return 0;}int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}

3. AVL树与红黑树

插入时要维护其绝对平衡,旋转的次数比较多,如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合

红黑树不追
求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,
所以在经常进行增删的结构中性能比AVL树更优

  1. AVL树和红黑树都是平衡二叉树。在查询效率方面,AVL树追求绝对平衡,红黑树要求最长路径不超过最短路径的两倍,AVL查询数据效率比红黑树高,但是对于CPU而言,都是属于logN这个量级的。
  2. AVL树追求控制严格平衡是需要付出代价的,插入和删除已需要进行大量的旋转。红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在插入和删除方面红黑树效率更高。
  3. 综上,红黑书更优,实际运用的多。

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

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

相关文章

爬虫 — App 爬虫(二)

目录 一、Appium介绍二、node.js 安装三、Java 的 SDK 安装以及配置1、安装步骤2、配置环境变量 四、安卓环境的配置1、配置环境变量 五、Appium 安装1、安装2、打开 APP3、使用 六、Appium 使用1、定位数据&#xff08;方法一&#xff0c;不常用&#xff09;2、定位数据&#…

磁盘检测工具DiskInfo下载

网址&#xff1a;Download - Crystal Dew World [en] (crystalmark.info) PS:乍一看还以为是什么二次元网站 划到这里&#xff0c;下载zip 等待一会就会自动弹出下载了 选择合适的位置即可

token登录的实现

token登录的实现 我这种token只是简单的实现token&#xff0c;就是后端利用UUID 生成简单随机码&#xff0c;利用随机码作为在Redis中的键&#xff0c;然后存储的用户信息作为值&#xff0c;在每次合理请求的时候对token的有效时间进行刷新&#xff08;利用拦截器&#xff09;&…

FPGA project : DS18B20

本想着一天发一个实验的&#xff0c;这个ds18b20&#xff0c;耗时两天。代码写了两次&#xff0c;呜呜~ 由于第二次写代码没画时序图&#xff0c;所以代码和时序图一些参数有些不一致&#xff0c;但问题不大。 这里有几件事情值得一提&#xff1a; 1&#xff1a;关于状态机的…

ceph分布式存储

ceph特点 Ceph项目最早起源于Sage就读博士期间的工作&#xff08;最早的成果于2004年发表&#xff09;&#xff0c;并随后贡献给开源社区。在经过了数年的发展之后&#xff0c;目前已得到众多云计算厂商的支持并被广泛应用。RedHat及OpenStack都可与Ceph整合以支持虚拟机镜像的…

【C语言】求一个整数的二进制序列中1的个数的三种方法

方法一&#xff1a;逐位%2法 该方法的初步测试代码如下: int NumberOf1(int n) {int count 0;while (n){if (n % 2 1){count;}n n / 2;}return count; } 众所周知&#xff0c;数据在内存里以补码的形式存储&#xff0c;这是为了简化计算机的结构设计&#xff0c;同时也提…

【数据结构】哈希表(详)

文章目录 前言正文一、基本概念二、基本原理1.哈希函数1.1直接定址法&#xff08;常用&#xff09;1.2除留余数法&#xff08;常用&#xff09;1.3 平方取中法&#xff08;了解&#xff09;1.4 折叠法(了解)1.5 随机数法(了解)1.6数学分析法(了解) 2.哈希冲突2.1 平均查找长度2…

Python —— excel文件操作(超详细)

背景 很多公司还是用excel去管理测试用例的&#xff0c;所以为了减少重复繁琐的导出导出工作&#xff0c;学会如何用代码操作excel表格很实用~ 1、读取excel文件基本步骤 1、操作excel的一些库 1、xlrd&#xff1a;读取库&#xff0c;xlwt&#xff1a;写入&#xff0c;现在…

No servers available for service: renren…。 Gateway 网关报503错误 ,已解决

目录 环境配置问题描述loadbalancer的作用 环境配置 问题描述 配置spring cloud gateway使用端口访问就可以&#xff0c;使用lb:// 就报503 gateway:routes:- id: admin_routeuri: lb://gulimall-admin # uri: http://localhost:8080predicates:- Path/api/**filter…

蓝桥杯 题库 简单 每日十题 day7

01 啤酒和饮料 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。啤酒每罐2.3元&#xff0c;饮料每罐1.9元。小明买了若干啤酒和饮料&#xff0c;一共花了82.3元。我们还知道他买的啤酒比饮料的数量少&#xff0c;请你…

CVPR 2023 | UniMatch: 重新审视半监督语义分割中的强弱一致性

在这里和大家分享一下我们被CVPR 2023录用的工作"Revisiting Weak-to-Strong Consistency in Semi-Supervised Semantic Segmentation"。在本工作中&#xff0c;我们重新审视了半监督语义分割中的“强弱一致性”方法。我们首先发现&#xff0c;最基本的约束强弱一致性…

RHCE---时间服务器

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 Linux中的时间服务器是指NTP服务器&#xff0c;NTP是Network Time Protocol的缩写&#xff0c;即网络时间协议。NTP服务器可以提供精确的时间信息&#xff0c;从而使得网络上的所有设备都能…

C语言文件的相关操作

C语言中文件的相关操作 文件的打开 使用文件的打开函数需要引入这个头文件&#xff1a;#include <fcntl.h> open函数 int open(char const *pathname, int flags, mode_t mode) 功能&#xff1a;打开已有的文件或者创建新文件参数 pathname&#xff1a;文件路径名&…

基于Python+Tkinter实现一个贪食蛇小游戏

你是否还记得那个时代&#xff0c;当我们的手机还没有触摸屏&#xff0c;游戏也只有像“贪食蛇”这样的经典款&#xff1f;当时&#xff0c;许多人都沉迷于控制一条小蛇吃食物的乐趣中。而今&#xff0c;让我们利用Python和Tkinter&#xff0c;一起重温那个时代&#xff0c;制作…

C语言基础知识点(八)联合体和大小端模式

以下程序的输出是&#xff08;&#xff09; union myun {struct { int x, y, z;} u;int k; } a; int main() {a.u.x 4;a.u.y 5;a.u.z 6;a.k 0;printf("%d\n", a.u.x); } 小端模式 数据的低位放在低地址空间&#xff0c;数据的高位放在高地址空间 简记&#xff…

使用Java将PPT、PPTX和PDF转换为图片

从Office到图片—使用Java实现文件格式转换 PDF转图片1. 万事第一步2. 撸代码 PPT/PPTX转图片1. 万事第一步2. 撸代码验收一下 最近小雨遇到了一个需求&#xff0c;需要在前端小程序中嵌入展示Office文件的功能。然而&#xff0c;前端使用开源组件进行在线预览会导致性能消耗较…

R语言贝叶斯广义线性混合(多层次/水平/嵌套)模型GLMM、逻辑回归分析教育留级影响因素数据...

全文下载链接&#xff1a;http://tecdat.cn/?p24203 本教程使用R介绍了具有非信息先验的贝叶斯 GLM&#xff08;广义线性模型&#xff09; &#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 当前教程特别关注贝叶斯逻辑回归在二元结果和计数/比例结果场景中的…

基于SSM框架的《超市订单管理系统》Web项目开发(第四天)用户管理,增删改查(日期插件的使用)

基于SSM框架的《超市订单管理系统》Web项目开发&#xff08;第四天&#xff09;用户管理&#xff0c;增删改查&#xff08;日期插件的使用&#xff09; 昨天我们实现了多表关联查询&#xff0c;还有分页显示数据的功能。那么今天我们要继续完善用户管理这一模块。 今天要完成的…

clickhouse简单安装部署

目录 前言(来源于官方文档)&#xff1a; 一.下载并上传 1.下载地址&#xff1a;点我跳转下载 2.上传至Linux 二.解压和配置 1.解压顺序 注意&#xff1a;必须按照以下顺序解压&#xff0c;并且每解压一个都要执行该解压后文件的install/doinst.sh文件 解压步骤&#xff…

玩玩“小藤”开发者套件 Atlas 200I DK A2 之VSCode远程连接

玩玩“小藤”开发者套件 Atlas 200I DK A2 之VSCode远程连接 0. 背景1. VSCode 安装 Remote - SSH 插件2. 安装 OpenSSH 组件3. VSCode SSH 连接 Atlas 200I DK A24. 打开远程文件夹 0. 背景 总所周知&#xff0c;英伟达的GPU供不应求&#xff0c;还各种限制。华为推出了升腾A…