【C++ 高阶数据结构 Test】AVL ~ 二叉搜索树

文章目录

      • 1. AVL 树概念
      • 2. AVL 树节点的定义
      • 3. AVL树的插入
      • 4. AVL树的旋转
        • 4.1 新节点插入较高左子树的左侧---左左:右单旋
        • 4.2 新节点插入较高右子树的右侧---右右:左单旋
        • 4.3 新节点插入较高左子树的右侧---左右:先左单旋再右单旋
        • 4.4 新节点插入较高右子树的左侧---右左:先右单旋再左单旋
      • 5. AVL树的性能
      • 6. AVL树的面试题

1. AVL 树概念

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

🍎② 因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis (为什么叫 AVL 树呢 ? ----- 是从这两位科学家的姓名来的) 在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

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

  • Ⅰ、它的左右子树都是AVL树;
    Ⅱ、左右子树高度之差(简称平衡因子)的绝对值不超过1 (即:-1、0、1);

注意:
🐧a. 平衡因子不是 AVL树必须需要的,它只是 AVL 树的一种实现方式,平衡因子不是必须要维护的,在操作时也可以直接通过高度函数来算,只不过比较麻烦;

🐧b. 平衡因子 = 右子树的高度 - 左子树的高度。

在这里插入图片描述

结论: 如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 O ( l o g 2 n ) O(log_2 n) O(log2n) ,搜索时间复杂度O( l o g 2 n log_2 n log2n)。(注意,当 n = 3亿 的时候,二叉树的高度还不到 30,所以极大的提高了搜索效率)


2. AVL 树节点的定义

template<class K, class V>
struct AVLTreeNode {AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;		// AVL树要定义节点的父亲,因为更新需要更新祖先的平衡因子pair<K, V> _kv;int _bf;	// 该节点的平衡因子//构造函数,以便初始化AVLTreeNode(const pair<K, V>& kv): _left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0);	{}
};

3. AVL树的插入

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

🐧Ⅰ. 按照二叉搜索树的方式插入新节点
🐧Ⅱ. 调整插入节点以及该节点的祖先节点的平衡因子

a. 插入父节点的左边,父节点的平衡因子 -1

b. 插入父节点的右边,父节点的平衡因子 +1

c. 父亲的平衡因子 == 0的时候,表示父亲所在子树的高度不变,不再需要往上更新,插入结束

d. 父亲平衡因子 == 1 or -1,父亲所在子树高度变了,继续往上更新;

e. 父亲平衡因子== 2 or -2,父亲所在的子树已经不平衡了,需要旋转处理

注意: ❗更新平衡因子的结束条件,要么是当前更新的父亲平衡因子等于0,要么是当前更新节点是根节点,根节点的父亲的平衡因子是不存在的(因为此时父亲节点为空),即为结束条件。

在这里插入图片描述

4. AVL树的旋转

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



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

🍎 ①右单旋:必须要 单纯的满足都是左子树比右子树高的情况 不能出现右子树比左子树高的情况

🍎 ②什么情况下使用右单旋呢 ?

在这里插入图片描述

在这里插入图片描述

	//右单旋void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;// 先稳定老大parent->_left = subLR;// 认新主人if (subLR)subLR->_parent = parent;// 将老大变成老二subL->_right = parent;// 因为 parent 可能是还有父节点的情况的Node* ppNode = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;subL->_parent = nullptr;}else{//判断 parent 是 ppNode的左孩子还是右孩子if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}// 将其平衡因子改变parent->_bf = subL->_bf = 0;}

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

🍎 ① 什么情况下使用左单旋呢 ?

在这里插入图片描述


🍎 ② 注意:❗下面这种情况就不是左单旋,因为它不是单纯的右边高(它有左边高的情况

在这里插入图片描述


  • 以下是左单旋的例子:

在这里插入图片描述

	//左单旋void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;// 先稳定老大,给他派士兵parent->_right = subRL;if (subRL != nullptr)subRL->_parent = parent;// 老大变成老二subR->_left = parent;parent->_parent = subR;Node* ppNode = parent->_parent;if (parent == _root){_root = subR;subR->_parent = nullptr;}else{// 判断 parent 节点是在 ppNode的右节点还是左节点if (ppNode->_right == parent){ppNode->_right = subR;}else{ppNode->_left = subR;}subR->_parent = ppNode;}parent->_bf = subR->_bf = 0;}
4.3 新节点插入较高左子树的右侧—左右:先左单旋再右单旋

🍎 ① 大概的思路是将该二叉树变成满足完全右单旋的情况。

🍎 ② 什么情况下使用左右双旋呢 ?

在这里插入图片描述

在这里插入图片描述

// 先进行左单旋,再右单旋
void RotateLR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;// 旋转之前,保存subLR的平衡因子,旋转完成之后,需要根据该平衡因子来调整其他节点的平衡因子int bf = subLR->_bf;// 先对30进行左单旋RotateL(parent->_left);//  再对90进行右单旋RotateR(parent);// // 旋转之前,60的平衡因子可能是-1/0/1,旋转完成之后,根据情况对其他节点的平衡因子进行调整if (bf == -1){subLR->_bf = 0;subL->_bf = 0;parent->_bf = 1;}else if (bf == 1){subLR->_bf = 0;subL->_bf = -1;parent->_bf = 0;}else if (bf == 0){subLR->_bf = 0;subL->_bf = 0;parent->_bf = 0;}else{assert(false);}
}
4.4 新节点插入较高右子树的左侧—右左:先右单旋再左单旋

🍎 ① 什么情况下使用右左双旋呢 ?

在这里插入图片描述

在这里插入图片描述

// 右左单旋
void RotateRL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;}else{parent->_bf = 0;subR->_bf = 0;}
}

5. AVL树的性能

🐧🐧🐧 AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 l o g 2 ( N ) log_2 (N) log2(N)

🍎🍎🍎 但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入(插入的时候 new 出节点也很消耗时间)时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。

因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变,意思就是不会插入新数据),可以考虑AVL树,但一个结构经常修改,就不太适合。

6. AVL树的面试题

  • 🍎① AVL树插入或者删除的时候,其旋转情况?

🐧Ⅰ、插入时,AVL树最多只需要旋转两次。

🐧Ⅱ、删除操作时,可能不止旋转两次,可能需要旋转多次,子树旋转后,其高度降低了一层,其上层可能也需要跟着旋转。

在这里插入图片描述

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

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

相关文章

电工能混到这份上

最近看到某电工师傅发了一篇帖子&#xff0c;大致内容是他在处理一个简单故障的时候居然花了很长的时间。我们一起来看看他遇到的是什么故障吧! plc 控制的一台设备&#xff0c;行走部分靠 2 个脚踏开关控制&#xff08;内部开关量控制方向&#xff0c;电位器控制速度&#xff…

微信小程序快速开发-基础内容(内容真的又多又干货)

目录 实现横向布局效果 实现滚动效果 实现轮播图效果 实现文本长按选中复制效果 渲染 HTML 标签 按钮组件的使用效果 图片组件的使用效果 Mustache 语法 动态绑定内容&#xff08;定义变量&#xff0c;渲染变量&#xff09; 动态绑定属性&#xff08;将属性定义为变量…

用SwitchHosts模拟本地域名解析访问

一.用SwitchHosts模拟本地域名解析访问 1.下载地址 https://download.csdn.net/download/jinhuding/89313168 2.使用截图

软考-软件工程

软件工程概述 软件工程指的是应用计算机科学、数学及管理科学等原理&#xff0c;以工程化的原则和方法来解决软件 问题的工程&#xff0c;目的是提高软件生产率、提高软件质量、降低软件成本。 概述&#xff1a; 软件开发模型&#xff1a;指导软件开发的体系 需求分析确定软件…

谷歌外贸seo优化怎么做?

一般有两种选择&#xff0c;在大型电商平台开展业务&#xff0c;如亚马逊&#xff0c;阿里巴巴等平台&#xff0c;也可以选择搭建自己的独立站 选择在大型电商平台可以方便迅速建立起自己的商铺&#xff0c;不需要考虑太多交易&#xff0c;支付&#xff0c;物流等方面的问题&am…

ADS Momentum 仿真设置

1、选择Momenttum Microwave。 2、Layout不需要操作。 3、Partitioning 不需要操作。 4、没有叠层的话需要新建叠层&#xff0c;过孔可以在叠层中右键添加。 5、注意确认端口的Gnd Layer。 6、设置仿真频率。 7、Output Plan。 8、Option。 最后运行仿真&#xff0c;等待结果即…

【Python报错】Python安装模块时报错Fatal error in launcher

【Python报错】Python安装模块时报错Fatal error in launcher 最近需要用到python下载一个小工具&#xff0c;自信敲下回车键本想看到黑乎乎的终端上会出现快速跳跃的命令代码&#xff0c;没想到&#xff0c;报错了...... Fatal error in launcher: Unable to create process …

2024 年 6 月 银行从业资格考试(银从)如何备考?

文章目录 一、考试介绍&#xff08;已了解的自行跳过此步骤&#xff09;&#xff08;一&#xff09;含金量&#xff08;二&#xff09;就业方向&#xff08;三&#xff09;适合人群&#xff08;四&#xff09;报考条件&#xff08;五&#xff09;题型分值&#xff08;六&#x…

【Unity之FairyGUI】你了解FGUI吗,跨平台多功能高效UI插件

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

鸿蒙应用布局ArkUI:【其他常用布局容器和组件】介绍

其他常用布局容器和组件 创建轮播&#xff08;Swiper&#xff09;实现轮播图功能 开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 栅格布局&#xff08;GridRow/GridCol&#xff09;和Grid布局类似…

私活更好用:SpringBoot开源项目!!【送源码】

今天分享一款非常香的SpringBoot大屏开源项目&#xff0c;非常适合接私活用。 这是一款基于SpringBoot代码生成器的快速开发平台&#xff01;采用前后端分离架构&#xff1a;SpringBoot&#xff0c;Mybatis&#xff0c;Shiro&#xff0c;JWT&#xff0c;Vue&Ant Design。强…

高质量英文文献应该如何查找并且阅读?

1. 查找 使用谷歌学术进行论文关键字检索&#xff0c;查找高度匹配的论文。这里我们可以选择年限等信息进行筛选。作为研究者我们一般选择近三年的文章进行阅读。这里谷歌学术需要科学上网&#xff0c;请大家自行解决。 https://scholar.google.com/ 2. 查看期刊等级 我们查…