AVLTree代码刨析

news/2024/11/15 7:33:16/

AVLTree原理:

        AVLTree是高度平衡二叉树每一个节点的左右子树高度差都小于2,这是AVLTree高度平衡的由来,他是在平衡二叉树的基础上进行特殊的处理(旋转:如果该节点不满足高度平衡二叉树的特点就进行旋转 旋转目的是为了调整该节点左右子树高度差 促使其达到高度平衡二叉树

        AVLTree节点之间是通过三叉链(里面存有三个节点:_parent,_left,_right)进行链接的 这样做为了更好的用迭代器去遍历二叉树

        AVLTree缺点也很明显,旋转次数太多,但红黑树旋转就较少,所以AVLTree树的建立较耗时间,红黑树肯会更优。

补充:AVLTree就是为了更好的搜索查找而设计的,根据树的特点,深度越深所存的值就越多,查找也就越快,所以说该树主要为查找而生,实现删除功能会逆着之前的步骤进行调整,所以没有实现。我感觉重建二叉树也不会太费时间。

平衡原理:

        该篇AVLTree是通过平衡因子(balance fact)进行调整;

        平衡因子取值:0,1/-1,2/-2;

        通过左树新增节点父亲的平衡因子“--” 右树新增节点父亲的平衡因子“++”

        当父亲的平衡因子为2/-2时;说明左右子树高度差已经等于2了,不满足高度平衡二叉树,此时就要进行相应的旋转,如何进行旋转待会再细说。

        当父亲的平衡因子为1/-1时;继续向上更新,因为以该节点为根的树,还是高度平衡二叉树,但是不保证新增的节点对他的祖先不产生影响,有可能他的祖先平衡因子会变成2/-2,这样就会发生上述的旋转,所以要进行向上更新。

平衡二叉树的主要难点就是旋转 旋转搞清楚就没什么困难了。

平衡二叉树的旋转:

之前就提到过旋转是调整以该节点,为旋转轴的子树的高度,所以说旋转之后该树已经是平衡二叉树了,所以不用再向上更新平衡因子。平衡因子会在每次旋转之后进行更新。

注意:AVLTree旋转使创始者规定的,这样做肯定是更好的,所以不要产生疑问,如为什么要这样旋转,为什么不是那样旋转?必须遵循AVLTree的旋转规则,一步一步画图去走

我的建议:看懂以后,需要反复去练习,这里面运用的知识还是挺多的,如树,平衡二叉树,节点之间的链接(与链表链接十分相似),大大提高知识的运用与理解

右旋:

        右旋示例图:

        右边高了,必须使右边降下来,构成平衡二叉树,旋转过程如下图:

代码如下:

	void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;//建立parent与subRL之间的关系parent->_right = subRL;if (subRL){subRL->_parent = parent;}//建立parent与subR之间的关系Node* ppNode = parent->_parent;parent->_parent = subR;subR->_left = parent;if (ppNode == nullptr){_root = subR;subR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}subR->bf = parent->bf = 0;//平衡因子的更新}

平衡因子更新如上图所示,根据旋转之后的图,调整平衡因子。

左旋:

        左旋示例图:

        左边高了,必须使左边降下来,构成平衡二叉树,旋转过程如下图:

代码如下:

	void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR){subLR->_parent = parent;}Node* ppNode = parent->_parent;subL->_right = parent;parent->_parent = subL;if (ppNode == nullptr){_root = subL;subL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}subL->bf = parent->bf = 0;}

平衡因子更新如上图所示,根据旋转之后的图,调整平衡因子。 

左右旋:

        该新增节点使根节点的左右子树不能构成平衡二叉树,需要进行旋转调整高度差,旋转过程如下图:

没有更新旋转过程的平衡因子,但是每个旋转函数中,都会对平衡因子进行更新,只是我没有在图上更新,旋转最终平衡因子可以根据图去更新

上面三种图,对应代码中三种情况的平衡因子更新,可能顺序有点乱。

代码如下:

	void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->bf;RotateL(subL);//左旋RotateR(parent);//右旋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);	}}

右左旋:

           该新增节点使根节点的左右子树不能构成平衡二叉树,需要进行旋转调整高度差,旋转过程如下图:

没有更新旋转过程的平衡因子,但是每个旋转函数中,都会对平衡因子进行更新,只是我没有在图上更新,旋转最终平衡因子可以根据图去更新

上面三种图,对应代码中三种情况的平衡因子更新,可能顺序有点乱。

代码如下:

	void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->bf;RotateR(subR);//右旋RotateL(parent);//左旋if (bf == -1)//左子树新增{subRL->bf = 0;subR->bf = 1;parent->bf = 0;}else if (bf == 1)//右子树新增{subRL->bf = 0;subR->bf = 0;parent->bf = -1;}else if(bf == 0)//本身是新增{subRL->bf = 0;subR->bf = 0;parent->bf = 0;}else{assert(false);}}

以上是平衡二叉树的旋转代码实现,如果不对请指教,

平衡二叉树的遍历:

平衡二叉树的遍历采用中序遍历,原因是平衡二叉树左子树始终小于根节点,根节点始终小于右子树,而中序遍历正好是:左,中,右,正好是升序遍历所以采用中序遍历

	void Inorder(){_Inorder(_root);}void _Inorder(Node* root){if (root == nullptr){return;}_Inorder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_Inorder(root->_right);}

平衡二叉树的判断:

平衡二叉树:左右子树高度差不超过1。

LCR 175. 计算二叉树的深度

平衡因子:就是右子树高度减左子树高度,其差值(可正负)就是平衡因子。

LCR 176. 判断是否为平衡二叉树

同时上面两个条件也可以做两个题。

​	int Height(Node* root){if (root == nullptr){return 0;}int lh = Height(root->_left);int rh = Height(root->_right);return lh > rh ? lh + 1 : rh + 1;}bool IsBalance(){return _IsBalance(_root);}bool _IsBalance(Node* root){if (root == nullptr){return true;}int lh = Height(root->_left);int rh = Height(root->_right);if (rh - lh != root->bf){cout << "平衡因子异常" << endl;return false;}return abs(rh - lh) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}

以上是通过平衡因子进行判断旋转,有的可能是通过计算该节点左右子树的高度差进行旋转,道理是一样的,平衡因子就是右子树高度减左子树高度得到的值(可正负)。

以上就是AVLTree的重要内容,有什么疑惑或者文章错误请指教~

下期发布红黑树讲解


http://www.ppmy.cn/news/1140660.html

相关文章

【算法小课堂】二分查找算法

简单思路&#xff1a; 当我们要从一个序列中查找一个元素的时候&#xff0c;最快想到的方法就是顺序查找法&#xff08;即&#xff1a;从前到后依次查找&#xff09;。但这种方法过于无脑&#xff0c;就是暴力的把每个元素都排查一遍。元素个数少的时候还行&#xff0c;一旦元…

MySql 终端常用指令

一、开发背景 利用数据库实现数据的增删改查 二、开发环境 Window10 mysql-8.0.33-win64 三、实现步骤 1、管理员模式打开终端 2、登录数据库&#xff08;停止 开启 登录&#xff09; 具体指令参考 MySql 安装篇 ​​​​​​​ ​​…

wc命令使用指南 | 教你如何高效统计文件字数、行数和字符数

文章目录 wc命令使用指南1. 引言1.1 什么是wc命令&#xff1f;1.2 wc命令的作用和用途1.3 wc命令的常用参数 2. 基本使用2.1 安装和启动wc命令2.2 统计文件的行数2.3 统计文件的字数2.4 统计文件的字符数2.5 统计文件的词数2.6 统计文件的最长行长度 3. 高级使用3.1 统计多个文…

java CPU 或者内存 异常排查

java CPU 或者内存 异常排查 提示&#xff1a;需要基础环境和配置上java-home CPU 或者内存 异常排查 java CPU 或者内存 异常排查前言一、java文件上传&#xff08;Test.java&#xff09;二、转换为class三、执行命令&#xff0c;启动文件四、使用top命令查看五、下载文件&…

AP2400 LED电源驱动 降压恒流IC 机场灯 指示灯 交通照明灯

产品描述 AP2400 是一款 PWM 工作模式,高效率、外围简单、外驱功率管&#xff0c;适用于 5-100V输入的高精度降压 LED 恒流驱动芯片。外驱 MOS&#xff0c;最大输出电流可达 6A。AP2400 可实现三段功能切换&#xff0c;通过MODE1/2/3 切换三种功能模式&#xff1a;全亮&#xf…

基于springboot的论坛网站

目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 普通管理员管理 交流论坛 交流论坛评论 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了…

git stash详解

stash:保存现场 1.建议&#xff08;规范&#xff09; &#xff1a;在功能未没有开发完毕前&#xff0c;不要commit 2.规定&#xff08;必须&#xff09; &#xff1a; 在没有commit之前&#xff0c;不能chekcout切换分支 &#xff08;不在同一个commit阶段&#xff09; 如果还没…

Android App启动优化之启动框架

android启动优化是个比较重要的部分&#xff0c;也是一大难题&#xff0c;一个优秀的app首先给人第一感觉就是启动速度&#xff0c;启动速度非常影响用户的体验&#xff0c;那么我们今天展开说说启动优化相关的问题。 我们先来简单分析一下启动过程、启动优化方向&#xff0c;…