当前位置: 首页 > news >正文

hello树先生——AVL树

AVL树

  • 一.什么是AVL树
  • 二.AVL树的结构
    • 1.AVL树的节点结构
    • 2.插入函数
    • 3.旋转调整
  • 三.平衡测试

一.什么是AVL树

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
AVL树的性质:

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
  • 如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 O ( l o g 2 n ) O(log_2 n) O(log2n)
    在这里插入图片描述

二.AVL树的结构

1.AVL树的节点结构

template<class K, class V>
struct AVLTreeNode
{AVLTreeNode* _left;AVLTreeNode* _right;AVLTreeNode* _parent;pair<K, V> _kv;int _bf;AVLTreeNode(const pair<K,V>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_bf(0){}
};

这里的数据存储使用pair类型的数据对,将key索引与对应数据value存储,增加了_parent保存父亲节点,增加了_bf平衡因子来衡量左右子树是否平衡。

2.插入函数

bool insert(const pair<K, V>& kv)

这里插入方式与搜索二叉树一致,只是在后面增加了平衡调整的步骤

//如果根为空if (_root == nullptr){_root = new node(kv);return true;}//找到目标值node* parent = nullptr;node* cur = _root;while (cur){//key < curif (kv.first < cur->_kv.first){parent = cur;cur = cur->_left;}else if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else{//查重return false;}}//插入目标值cur = new node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;

调节平衡因子

while(parent)
{
//向上更新
}

如果插在左子树,则平衡因子–,否则++

if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}

判断平衡因子是否正常倘若>=2则需要旋转

			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){//需要旋转//左左高,右单旋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);}break;}else{//大问题assert(false);}

3.旋转调整

AVL树的旋转分为四种,左单旋,右单旋,左右双旋和右左双旋。

1.右单旋

	void rotater(node* parent)

在这里插入图片描述
当插入new节点时,60节点会左右失衡,我们称60为parent,30为subl,则平衡因子会分别变为-2,-1,成为左左高模型,此时使用右单旋。
由于搜索树特性:30<b<60<c,所以可以将右方降下去,从而达到平衡。

  • 传入旋转点parent

  • 记录关键节点,防止旋转后丢失
    在这里插入图片描述

		node* subl = parent->_left;node* sublr = subl->_right;
  • 将parent的左指向sublr,若sublr为空节点,则不链接父亲节点否则链接
  • 将subl的右指向parent,同时链接父亲节点
		parent->_left = sublr;if (sublr)sublr->_parent = parent;subl->_right = parent;parent->_parent = subl;//保存父节点node* ppnode = parent->_parent;subl->_parent = ppnode;
  • 考虑parent是否为根,是否链接parent的父亲节点
		//考虑parent是否为根if (ppnode == nullptr){_root = subl;subl->_parent = nullptr;}else{subl->_parent = ppnode;if (ppnode->_left == parent){ppnode->_left = subl;}else{ppnode->_right = subl;}}
  • 修改平衡因子
parent->_bf = subl->_bf = 0;

2.左单旋
大体思路与右单旋相同
在这里插入图片描述

	void rotatel(node* parent){node* subr = parent->_right;node* subrl = subr->_left;parent->_right = subrl;if (subrl)subrl->_parent = parent;subr->_left = parent;//保存父节点node* ppnode = parent->_parent;parent->_parent = subr;subr->_parent = ppnode;//考虑parent是否为根if (ppnode == nullptr){_root = subr;subr->_parent = nullptr;}else{subr->_parent = ppnode;if (ppnode->_left == parent){ppnode->_left = subr;}else{ppnode->_right = subr;}}//调节平衡因子parent->_bf = subr->_bf = 0;}

3.左右双旋

void rotatelr(node* parent)

通常双旋有三种情况,在b里插入新节点,在c里插入新节点,或者b,c都为空
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

记录sul的平衡因子,方便判断是哪种情况

		node* subl = parent->_left;node* sublr = subl->_right;int bf = subl->_bf;rotatel(subl);rotater(parent);
		if (bf == -1){subl->_bf = 0;parent = 1;}else if (bf == 1){subl->_bf = -1;parent->_bf = 0;}else if (bf == 0){subl->_bf = 0;parent->_bf = 0;}sublr->_bf = 0;

每一种情况平衡因子不同,所以需要画图分别讨论
** 4.右左双旋**

void rotaterl(node* parent){node* subr = parent->_right;node* subrl = subr->_left;int bf = subr->_bf;rotater(subr);rotater(parent);if (bf == -1){subr->_bf = 1;parent = 0;}else if (bf == 1){subr->_bf = 0;parent->_bf = -1;}else if (bf == 0){subr->_bf = 0;parent->_bf = 0;}subrl->_bf = 0;}

三.平衡测试

判断是否平衡

    bool _IsBalance(node* root){if (root == nullptr){return true;}int leftheight = _height(root->_left);int rightheight = _height(root->_right);if (abs(leftheight - rightheight) >= 2){return false;}//判断节点平衡因子是否正确if (root->_bf != (rightheight - leftheight)){return false;}return _IsBalance(root->_left) && _IsBalance(root->_right);}

在这里插入图片描述
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 深入了解linux下TCP并发服务器和IO模型的实现
  • C++:list篇
  • 【60天备战软考高级系统架构设计师——第四天:需求获取与初步分析】
  • 站长神器,AI批量生成原创文章工具免费用还能自动发布到站点
  • Mysql-redo logs,binlog以及undo logs的作用及区别
  • llm 是泡沫?
  • 软件测试工程师必备的技术能力
  • 【通过h5作为中转页跳转到微信小程序】
  • LMDeploy 量化部署进阶实践
  • c++中的匿名对象及内存管理及模版初阶
  • 【自用16.】C++类
  • 组合式API-reactive和ref函数,computed计算属性,watch函数
  • Linux和Unix的区别及为什么鸿蒙系统不用Unix的原因
  • 排序算法(冒泡、插入、选择、快排、归并)原理动画及Python、Java实现
  • 进程、线程的区别
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • AHK 中 = 和 == 等比较运算符的用法
  • DataBase in Android
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • java 多线程基础, 我觉得还是有必要看看的
  • java小心机(3)| 浅析finalize()
  • JS题目及答案整理
  • Linux CTF 逆向入门
  • MobX
  • SpringBoot 实战 (三) | 配置文件详解
  • Sublime Text 2/3 绑定Eclipse快捷键
  • Vue官网教程学习过程中值得记录的一些事情
  • vue学习系列(二)vue-cli
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 飞驰在Mesos的涡轮引擎上
  • 如何解决微信端直接跳WAP端
  • 入口文件开始,分析Vue源码实现
  • 学习Vue.js的五个小例子
  • 一道闭包题引发的思考
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 用element的upload组件实现多图片上传和压缩
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • # Apache SeaTunnel 究竟是什么?
  • #DBA杂记1
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • #经典论文 异质山坡的物理模型 2 有效导水率
  • (003)SlickEdit Unity的补全
  • (42)STM32——LCD显示屏实验笔记
  • (52)只出现一次的数字III
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (二)原生js案例之数码时钟计时
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (论文阅读30/100)Convolutional Pose Machines
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像