二叉树之AVL树

文章目录

    • 1. AVL树的概念(logN)
      • 1.1背景
      • 1.2规则
    • 2.AVL树节点的定义
    • 3.AVL树的插入
    • 4. AVL树的旋转(重点)
      • 4.1 新节点插入较高的右子树的右侧:左单璇;
      • 4.2 新节点插入较高左子树的左侧:右单璇;
      • 4.3(双旋) 新节点插入较高右子树的左侧---右左:先右单旋再左单旋
        • 4.3.1添加节点位置的三种情况
      • 4.4 新节点插入较高左子树的右侧---左右:先左单旋再右单旋
    • 5.判断AVL树是否平衡

1. AVL树的概念(logN)

1.1背景

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树查找元素相当于在顺序表中搜索元素效率低下

1.2规则

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

平衡因子:右子树节点个数减左子树的个数

注意:平衡因子不是必须的,只是辅助;

问题:为什么平衡因子不能超过1呢;
原因:因为实现不了0,最低的高度差就是1;

2.AVL树节点的定义

AVL树节点的定义

template<class T>
struct AVLTreeNode
{AVLTreeNode(const T& data): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _bf(0){}AVLTreeNode<T>* _pLeft;   // 该节点的左孩子AVLTreeNode<T>* _pRight;  // 该节点的右孩子AVLTreeNode<T>* _pParent; // 该节点的双亲T _data;int _bf;                  // 该节点的平衡因子
};

3.AVL树的插入

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

  1. 按照二叉搜索树的方式插入新节点
  2. 调整节点的平衡因子
bool Insert(const T& data)
{// 1. 先按照二叉搜索树的规则将节点插入到AVL树中// ...// 2. 新节点插入后,AVL树的平衡性可能会遭到破坏,此时就需要更新平衡因子,并检测是否
破坏了AVL树//   的平衡性/*pCur插入后,pParent的平衡因子一定需要调整,在插入之前,pParent的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:1. 如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1即可2. 如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1即可此时:pParent的平衡因子可能有三种情况:0,正负1, 正负21. 如果pParent的平衡因子为0,说明插入之前pParent的平衡因子为正负1,插入后被调整
成0,此时满足AVL树的性质,插入成功2. 如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更
新成正负1,此时以pParent为根的树的高度增加,需要继续向上更新3. 如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进
行旋转处理*/while (pParent){// 更新双亲的平衡因子if (pCur == pParent->_pLeft)pParent->_bf--;elsepParent->_bf++;// 更新后检测双亲的平衡因子if (0 == pParent->_bf){    break;}else if (1 == pParent->_bf || -1 == pParent->_bf){// 插入前双亲的平衡因子是0,插入后双亲的平衡因为为1 或者 -1 ,说明以双亲
为根的二叉树// 的高度增加了一层,因此需要继续向上调整pCur = pParent;pParent = pCur->_pParent;}else{// 双亲的平衡因子为正负2,违反了AVL树的平衡性,需要对以pParent// 为根的树进行旋转处理if(2 == pParent->_bf){// ...}else{// ...}}}return true;
}

4. AVL树的旋转(重点)

如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:
注意:前两者是单旋他们的模型是相同的;
后俩者是双旋他们的模型相同;
在这里插入图片描述

4.1 新节点插入较高的右子树的右侧:左单璇;

左单璇的情况是:根的左子树是单身汉(成对的少);
解决方法:将根右子树的左子树过继根的左子树的右子树;这样根的右子树就帮了根的忙;根就认了右子树为义父;
在这里插入图片描述
代码实现

	void _RotateL(Node* pParent){Node* ppParent = pParent->_parent;Node* rChild = pParent->_right;Node* rlChild = pParent->_right->_left;rChild->_left = pParent;pParent->_right = rlChild;if(rlChild)//这里判断rlchild是否为空rlChild->_parent = pParent;pParent->_parent = rChild;if (_root == pParent){_root = rChild;rChild->_parent = nullptr;}else{if (ppParent->_right == pParent){ppParent->_right = rChild;}else{ppParent->_left = rChild;}rChild->_parent = ppParent;}pParent->_bf = rChild->_bf = 0;//这里的目的就是将者里的2和1的节点干成0;}

4.2 新节点插入较高左子树的左侧:右单璇;

在这里插入图片描述
代码实现

void _RotateR(Node* pParent){Node* ppParent = pParent->_parent;Node* lChild = pParent->_left;Node* lrChild = pParent->_left->_right;lChild->_right = pParent;pParent->_left = lrChild;if (lrChild)//这里判断rlchild是否为空lrChild->_parent = pParent;pParent->_parent = lChild;if (_root == pParent){_root = lChild;lChild->_parent = nullptr;}else{if (ppParent->_right == pParent){ppParent->_right = lChild;}else{ppParent->_left = lChild;}lChild->_parent = ppParent;}pParent->_bf = lChild->_bf = 0;//这里的目的就是将者里的2和1的节点干成0;}

4.3(双旋) 新节点插入较高右子树的左侧—右左:先右单旋再左单旋

4.3.1添加节点位置的三种情况

在这里插入图片描述
代码实现

//主函数
else if (parent->_bf == -2 && cur->_bf == 1){RotateR(parent);}
//函数体
void _RotateRL(Node* pParent){_RotateR(pParent->_right);_RotateL(pParent);Node* subR = pParent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;if (bf == -1){subRL->_bf = 0;subR->_bf = 1;pParent->_bf = 0;}else if (bf == -1){subRL->_bf = 0;subR->_bf = 0;pParent->_bf = -1;}else if (bf == 0){subRL->_bf = 0;subR->_bf = 0;pParent->_bf = 0;}else{assert(false);}}

4.4 新节点插入较高左子树的右侧—左右:先左单旋再右单旋

在这里插入图片描述

5.判断AVL树是否平衡

这里不可以使用遍历平衡因子,原因:平衡因子有可能是错的;
使用左右子树的高度想减的方法:

	//先想空//在使用递归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;}bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);if (rightHeight - leftHeight != root->_bf){cout << root->_kv.first << "平衡因子异常" << endl;return false;}return abs(rightHeight - leftHeight) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}

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

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

相关文章

AJAX——ajax原理

1.XMLHttpRequest 定义&#xff1a;XMLHttpRequest&#xff08;XHR&#xff09;对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL&#xff0c;获取数据。这允许网页在不影响用户操作的情况下&#xff0c;更新页面的局部内容。XMLHttpRequest在AJA…

数据输入输出流(I/O)

文章目录 前言一、数据输入输出流是什么&#xff1f;二、使用方法 1.DataInputStream类2.DataOutoutStream类3.实操展示总结 前言 数据输入输出流也是将文件输入输出流打包后使用的对象。相比于文件输入输出流&#xff0c;数据输入输出流提供了简单易用的方法去操作不同类型的数…

【FreeRTOS】常用API接口

【FreeRTOS】常用API接口 为方便快速检索&#xff0c;这里只留下对应的接口名和功能注释&#xff0c;具体传参和使用方法拿函数名百度搜。 任务相关 xTaskCreate() //创建任务 vTaskDelete( NULL ); //删除任务&#xff0c;传入NULL为删除当前的任务 vTaskStartScheduler()&…

【微服务】spring读取配置文件多种方式深入详解

目录 一、前言 二、java配置文件介绍 2.1 java配置文件产生原因 2.2 项目使用配置文件好处 2.3 springboot项目配置文件的必要性 2.4 微服务架构下配置文件使用场景 三、java读取配置文件常用方法 3.1 使用Properties类读取配置文件 3.1.1 使用getResourceAsStream读取…

时序分析基础(6)——input delay时序分析

1 简介 FPGA对于外部的时钟以及数据的延时信息是不知道的&#xff0c;在低速时钟且时钟发射沿在数据正中心的时候&#xff0c;一般可以不做约束来直接使用。但是到了高速时钟或者双沿采样或者发射沿和数据对齐的情况下&#xff0c;这时候就需要告诉VIVADO外部的时钟与数据情况来…

多轴机械臂/正逆解/轨迹规划/机器人运动学/Matlab/DH法 学习记录03——机械臂运动学逆解

系列文章目录 本科毕设正在做多轴机械臂相关的内容&#xff0c;这里是一个学习机械臂运动学课程的相关记录。 如有任何问题&#xff0c;可发邮件至layraliufoxmail.com问询。 1. 数学基础 2. 机械臂几何法与DH表示法 3. 机械臂运动学逆解 文章目录 系列文章目录一、引言1.手臂…

文件系统和软硬链接

文章目录 文件系统磁盘磁盘逻辑抽象inode 软硬链接软链接硬链接 文件系统 文件分为打开的文件和没有被打开的文件&#xff0c;而只有打开的文件是在内存的&#xff0c;也就是我们之前讲的&#xff0c;然而大部分文件都不是被打开的(当前不需要被访问的)&#xff0c;它们都在磁…

硬盘日常使用中的注意事项

硬盘是计算机中的重要存储设备,负责存储大量的数据。为了确保数据的完整性和硬盘的寿命,日常使用中需要注意以下几点: 避免震动和撞击:硬盘在工作时,内部的磁盘正在高速旋转,任何轻微的震动或撞击都可能导致磁盘损坏或数据丢失。因此,使用硬盘时应确保计算机放置稳定,避…

输电线路运行特性及简单电力系统潮流估算(二)

本篇为本科课程《电力系统稳态分析》的笔记。 本篇为这一章的第二篇笔记。上一篇传送门&#xff0c;下一篇传送门。 输电线路的运行特性 输电线路的空载运行特性 线路的等值电路如图所示。 由于是空载&#xff0c;则 S ~ 2 0 \widetilde{S}_20 S 2​0&#xff0c;可以计算…

4月阿里offer被毁,我该怎么进字节?

在校招求职的浪潮中&#xff0c;有些故事总是让人唏嘘不已。比如最近在社交平台上广泛讨论的一个话题&#xff1a;“4月阿里offer被毁&#xff0c;我该怎么进字节&#xff1f;”这不仅反映了当下职场的变动性&#xff0c;也映射了求职者在面对突如其来的变故时的无助与挣扎。 …

QT 按钮的工具提示tooltips设置字体大小颜色与背景

QT 按钮的工具提示tooltips设置字体颜色与背景 main.cpp添加 mainwindow.cpp添加全局配置&#xff1a; 构造函数中&#xff1a; QToolTip::setFont(font3); //按钮提示信息通用设置 如下&#xff1a; MainWindow_oq::MainWindow_oq(QWidget *parent) : QMainWindow(parent)…

光伏电站智能勘探:无人机优势及流程详解

随着科技和互联网技术的不断发展&#xff0c;无人机在各个领域的应用越来越广泛&#xff0c;其中之一就是光伏电站智能勘探。利用无人机高清摄像头和传感器等设备&#xff0c;可以对光伏电站周边环境、日照情况、房屋状态进行全方面的勘探和记录&#xff0c;搭配卫星勘探、实地…

C语言中scanf、gets、fgets的区别

scanf、gets和fgets都是C语言中用于从标准输入读取数据的函数&#xff0c;但它们之间存在一些重要的差异&#xff1a; scanf&#xff1a; scanf是一个格式化输入函数&#xff0c;它可以根据指定的格式从标准输入读取数据。使用scanf读取字符串时&#xff0c;需要小心处理缓冲区…

springboot注解开发如何映射对象型数据

创作灵感 最近在帮学校写一款小程序时&#xff0c;有这样一个数据需要展示&#xff1a;一条申请记录&#xff0c;里面包含了申请时间、申请状态、申请所提供的六条活动记录等待&#xff0c;其中&#xff0c;申请所提供的六条活动记录为一个数组&#xff0c;数组中的每个元素又…

【BUG】Hexo|GET _MG_0001.JPG 404 (Not Found),hexo博客搭建过程图片路径正确却找不到图片

我的问题 我查了好多资料&#xff0c;结果原因是图片名称开头是_则该文件会被忽略。。。我注意到网上并没有提到这个问题&#xff0c;遂补了一下这篇博客并且汇总了我找到的所有解决办法。 具体检查方式&#xff1a; hexo生成一下静态资源&#xff1a; hexo g会发现这张图片…

二维码门楼牌管理应用平台建设:网格化管理的新篇章

文章目录 前言一、二维码门楼牌管理应用平台的建设背景二、二维码门楼牌管理应用平台的功能特点三、二维码门楼牌管理应用平台的实际应用四、二维码门楼牌管理应用平台的前景展望 前言 随着信息技术的飞速发展&#xff0c;二维码门楼牌管理应用平台的建设已成为城市网格化管理…

李廉洋:4.20国际黄金,原油本周行情分析及下周一走势分析。

荷兰国际银行表示&#xff0c;所谓的美国国债期限溢价的回升&#xff0c;将为10年期国债收益率重返5%的关键水平铺平道路。从理论上来说&#xff0c;可将10年期美债收益率拆解为未来短端利率的期望期限溢价(term premium)。所谓期限溢价&#xff0c;是对投资者持有长期债券的风…

第十四届蓝桥杯省赛C/C++大学B组真题-飞机降落

思路&#xff1a;根据数据范围N<10猜测用DFS剪枝&#xff0c;因为菜狗不会状压dp。根据题目&#xff0c;一般这种飞机的题都会用到贪心的思想。思想是每架飞机都要卡极限最早降落时间&#xff0c;从而保证后面的飞机能够有充足时间降落。 代码参考博客MQy大佬有详细解答 #i…

深度学习之CNN

目录 我们为什么要用CNN&#xff0c;或者说究竟是因为什么我们要用CNN 卷积操作的实现原理 补充知识 torch.nn.Conv2d&#xff08;&#xff09; 注意 torch.nn.functional.conv2d&#xff08;&#xff09; torch.nn.functional.conv2d&#xff08;&#xff09;和torch.nn.…

Fannel和Calico

一 1、路由器下面每一个端口都是一个vlan,隔离了广播包 192.168.1.0和192.168.2.0他们属于不同的vlan,没有三层交换机或者路由器,他们通不了信 不在同一个vlan,也就是子网,包就会走向网关(也就是路由器那里,路由器有路由表。查看目的地192.168.2.0在b口,从b口出去vlan…