96SEO 2026-02-19 20:19 12
2代码实现2.左单旋的情况以及具体操作抽象图代码实现3.右左双旋的情况以及具体操作抽象图h

23.左右双旋的情况以及具体操作抽象图5.总结6.完整实现代码7.验证概念主程序代码8.性能总结前言
前面我们介绍了STL中的关联式容器map/set/multimap/mutiset等我们可以发现它们的底层都是按照二叉搜索树来实现的但是二叉搜索树自身有一些缺陷当往二叉搜索树中插入的元素有序或者接近有序二叉搜索树就会退化为单支其检索的时间复杂度就会退化为O(n)。
因此map、set等关联式容器的底层结构是对搜索二叉树进行平衡处理的平衡二叉搜索树。
普通的搜索二叉树一旦数据有序或者接近有序就会造成二叉搜索树退化为单支两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法
**当向二叉搜索树中插入新结点后如果能保证每个节点的左右子树高度之差不超过1需要对树中结点进行调整**即可降低树的高度从而减少平均搜索长度。
该树如果是空树那么它是AVL树它的左右子树是AVL树左右子树的高度差命名为平衡因子的绝对值不超过1可以是1/0/-1
上图的红色标识的是该结点的平衡因子这里的平衡因子使用右子树的高度减左子树的高度计算的。
假设该树有n个结点其高度应保持在O(log2n)O(log_2
n)O(log2n)搜索时间复杂度为O(log2nlog_2
实际上AVL树就是在二叉搜索树的基础上增加了平衡因子因此AVL树的插入可以分为两步
kv){//1.按照二叉搜索树的规则将节点插入到AVL树中node*
nullptr)//如果该树为空树直接插入新节点此时新节点是该树的根节点{_root
newnode;//2.对结点的平衡因子进行更新并检测新插入的结点是否破坏了AVL树的平衡性//调节平衡因子在插入新结点前pparent的平衡因子有以下三种情况-1,
1//如果cur插在pparent的左边给pparent的结点的平衡因子-1//如果cur插在pparent的右边给pparent的结点的平衡因子1//此时pparent的平衡因子有以下三种情况0±1±2//pparent平衡因子为0说明新插入结点不影响该子树的高度满足AVL树的性质不再进行调整//pparent平衡因子为±1说明插入前pparent的平衡因子为0此时以pparent为根的子树的高度加1需要继续向上更新平衡因子//pparent平衡因子为±2说明插入前pparent的平衡因子为±1此时pparent的平衡因子违反了AVL树的性质需要进行旋转操作while
(pParent)//当pParent为空时pParent就是根节点的父节点就不需要再进行调整了{//更新父节点的平衡因子if
pParent-_pleft){pParent-_bf--;}else
pParent-_pright){pParent-_bf;}//检测更新后的平衡因子if
pParent-_bf)//该子树的高度没变化不用调整{break;}else
pParent-_bf)//该子树的高度增加了1因此要继续向上调整平衡因子{cur
pParent-_pparent;}//3.破坏了AVL树的平衡性我们就要对以pparent为根的子树就地旋转处理//旋转的目的//1)让这棵子树的左右高度差不超过1//2旋转过程中保持它是搜索树//3更新旋转后的平衡因子//4让这棵树的高度与插入前保持一致不会继续影响上层不用继续向上调整else
pParent-_bf){//右单旋//我的平衡因子为-1父节点的平衡因子为-2.if
cur-_bf){RotateR(pParent);//更新平衡因子cur-_bf
cur-_bf){RotateL(pParent);//更新平衡因子cur-_bf
cur-_pright;RotateL(cur);RotateR(pParent);//更新平衡因子//新增结点就是SubRif
-1;}else{assert(false);}}//右左双旋else
cur-_pleft;RotateR(cur);RotateL(pParent);//更新平衡因子//新增结点就是SubLif
-1;}else{assert(false);}}return
true;}else//如果以上的程序哪里出现问题就会直接报错{assert(false);}}return
图中a,b,c是高度为h的子树红色数字是插入前该节点的平衡因子。
新增结点导致要向上更新平衡因子如果父节点的平衡因子为-2且当前结点的平衡因子为-1时我们就要进行右单旋。
要由具体的解决方法推出抽象的解决方法因此下面我们具体分析当h分别为0/1/2时我们的解决方法
0时在a处新增节点按照图中步骤使用右单旋对该子树进行调整最后更新平衡因子即可。
1时在a结点的左右子结点任意一个位置新增节点按照图中步骤使用右单旋对该子树进行调整最后更新平衡因子即可。
2时在a子树的i/j/m/n等四个位置的任意一个位置新增节点按照图中步骤使用右单旋对该子树进行调整最后更新平衡因子即可。
总结根据以上三种情况我们可以得出新增节点向上调整平衡因子的过程中如果出现父节点的平衡因子为-2当前结点的平衡因子为-1的情况就以父节点为轴进行右单旋之后更新父节点和当前结点的平衡因子为0即可。
parent-_pparent;//祖父parent-_pright
图中a,b,c是高度为h的子树红色数字是插入前该节点的平衡因子。
新增结点导致要向上更新平衡因子如果父节点的平衡因子为2且当前结点的平衡因子为1时我们就要进行左单旋。
可以看出当父节点为2且当前结点为1时需要以父节点为轴进行左单旋最后更新平衡因子。
parent-_pparent;//祖父parent-_pparent
我们设定结点值为30的结点是parent结点值为90的结点是pR,结点值为60的结点是pRL起名字后方便操作
右左双旋的抽象图其中a/d是高度为h的子树b/c是高度为h-1的子树
先以pR结点为轴进行右单旋再以parent结点为轴进行左单旋最后更新平衡因子即可。
我们设定结点值为90的结点是parent结点值为30的结点是pL,结点值为60的结点是pLR起名字后方便操作
先以pL结点为轴进行左单旋再以parent结点为轴进行右单旋最后更新平衡因子即可。
假如以parent为根的子树不平衡即parent的平衡因子为2/-2有以下几种情况
parent的平衡因子为2说明parent的右子树高设parent的右子树的根节点为pR
当pR的平衡因子为1时执行左单旋当pR的平衡因子为-1时执行右左双旋。
parent的平衡因子为-2说明parent的左子树高设parent的左子树的根节点为pL
当pL的平衡因子为-1执行右单旋当pL的平衡因子为1执行左右双旋。
旋转结束后原parent为根的子树高度已平衡不需要再向上更新。
node;AVLTree():_root(nullptr){}//左单旋(父节点平衡因子为2右孩子平衡因子为1void
parent-_pparent;//祖父parent-_pright
SubR;}}}//右单旋(父节点平衡因子为-2左孩子平衡因子为-1void
parent-_pparent;//祖父parent-_pparent
kv){//1.按照二叉搜索树的规则将节点插入到AVL树中node*
nullptr)//如果该树为空树直接插入新节点此时新节点是该树的根节点{_root
newnode;//2.对结点的平衡因子进行更新并检测新插入的结点是否破坏了AVL树的平衡性//调节平衡因子在插入新结点前pparent的平衡因子有以下三种情况-1,
1//如果cur插在pparent的左边给pparent的结点的平衡因子-1//如果cur插在pparent的右边给pparent的结点的平衡因子1//此时pparent的平衡因子有以下三种情况0±1±2//pparent平衡因子为0说明新插入结点不影响该子树的高度满足AVL树的性质不再进行调整//pparent平衡因子为±1说明插入前pparent的平衡因子为0此时以pparent为根的子树的高度加1需要继续向上更新平衡因子//pparent平衡因子为±2说明插入前pparent的平衡因子为±1此时pparent的平衡因子违反了AVL树的性质需要进行旋转操作while
(pParent)//当pParent为空时pParent就是根节点的父节点就不需要再进行调整了{//更新父节点的平衡因子if
pParent-_pleft){pParent-_bf--;}else
pParent-_pright){pParent-_bf;}//检测更新后的平衡因子if
pParent-_bf)//该子树的高度没变化不用调整{break;}else
pParent-_bf)//该子树的高度增加了1因此要继续向上调整平衡因子{cur
pParent-_pparent;}//3.破坏了AVL树的平衡性我们就要对以pparent为根的子树就地旋转处理//旋转的目的//1)让这棵子树的左右高度差不超过1//2旋转过程中保持它是搜索树//3更新旋转后的平衡因子//4让这棵树的高度与插入前保持一致不会继续影响上层不用继续向上调整else
pParent-_bf){//右单旋//我的平衡因子为-1父节点的平衡因子为-2.if
cur-_bf){RotateR(pParent);//更新平衡因子cur-_bf
cur-_bf){RotateL(pParent);//更新平衡因子cur-_bf
cur-_pright;RotateL(cur);RotateR(pParent);//更新平衡因子//新增结点就是SubRif
-1;}else{assert(false);}}//右左双旋else
cur-_pleft;RotateR(cur);RotateL(pParent);//更新平衡因子//新增结点就是SubLif
-1;}else{assert(false);}}return
true;}else//如果以上的程序哪里出现问题就会直接报错{assert(false);}}return
AVL树是在搜索二叉树的基础上加入了平衡因子的限制因此要验证AVL树可以分为以下两个步骤
每个结点子树高度差的绝对值不超过1判断结点中的平衡因子计算是否正确
下面是测试用的主程序代码大家可以用它来检验AVL树实现代码的正确性
_Height(Jinger::AVLnodeint,int*
_IsBalanceTree(Jinger::AVLnodeint,int*
计算pRoot节点的平衡因子即pRoot左右子树的高度差int
如果计算出的平衡因子与pRoot的平衡因子不相等或者pRoot平衡因子的绝对值超过1则一定不是AVL树if
pRoot的左和右如果都是AVL树则该树一定是AVL树return
;tree.insert(make_pair(it,it));}int
_IsBalanceTree(tree.Getroot());if
AVL树是一棵绝对平衡的搜索二叉树它要求每个结点的左右子树的高度差的绝对值不超过1这样可以保证查询时的时间复杂度log2(N)log_2(N)log2(N))。
但是如果对AVL树做一些结构修改的操作它的性能就会比较低下例如插入元素时要维护其绝对平衡的性质旋转的次数会比较多。
其中删除的效果最差有可能让旋转一直持续到根节点。
因此如果需要一种查询高效且有序的数据结构并且数据结构的个数为静态的不会发生改变可以考虑使用AVL树但是如果该结构需要经常被修改AVL树就不太适合了。
以上就是今天要讲的内容本文介绍了C中的AVL树的相关概念。
本文作者目前也是正在学习C相关的知识如果文章中的内容有错误或者不严谨的部分欢迎大家在评论区指出也欢迎大家在评论区提问、交流。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback