《AVL树完全解析:平衡之道与C++实现》

目录

  1. AVL树的核心概念
  2. 数据结构与节点定义
  3. 插入操作与平衡因子更新
  4. 旋转操作:从理论到代码
  5. 双旋场景深度剖析
  6. 平衡检测与测试策略
  7. 性能分析与工程实践
  8. 总结

0.前置知识:BS树

代码实现部分对和BS树相似的部分会省略。

1. AVL树的核心概念

1.1 平衡二叉搜索树的必要性

普通二叉搜索树(BST)在极端情况下会退化为链表,时间复杂度恶化至O(N)。AVL树通过强制平衡约束,将树高度严格控制在O(log N),确保所有操作的高效性。

1.2 AVL树的定义

  • 平衡条件:任意节点左右子树高度差绝对值≤1
  • 平衡因子(Balance Factor)
    合法取值范围:{-1, 0, 1}

1.3 历史背景

由前苏联科学家Adelson-Velsky和Landis于1962年提出,论文《An algorithm for the organization of information》首次描述这一数据结构。


2. 数据结构与节点定义

2.1 节点结构(C++实现)

template<class K, class V>
struct AVLTreeNode 
{std::pair<K, V> _kv;AVLTreeNode<K, V>* _left;   // 左子节点AVLTreeNode<K, V>* _right;  // 右子节点AVLTreeNode<K, V>* _parent; // 父节点(关键用于回溯更新)int _bf;                    // 平衡因子// 构造函数AVLTreeNode(const std::pair<K, V>& kv): _kv(kv), _left(nullptr), _right(nullptr),_parent(nullptr), _bf(0) {}
};

2.2 树类框架

template<class K, class V>
class AVLTree 
{typedef AVLTreeNode<K, V> Node;
public:// 接口方法bool Insert(const std::pair<K, V>& kv);Node* Find(const K& key);// ...
private:Node* _root = nullptr;// 旋转工具方法void RotateL(Node* parent);   // 左单旋void RotateR(Node* parent);   // 右单旋void RotateLR(Node* parent);  // 左右双旋void RotateRL(Node* parent);  // 右左双旋
};

3. 插入操作与平衡因子更新

3.1 插入流程

开始插入
根节点空?
创建新根节点
BST规则寻找插入位置
创建新节点并链接
回溯更新平衡因子
平衡因子是否失衡?
执行旋转调整
结束插入

3.2 平衡因子更新规则

  • 插入右子树:父节点bf++
  • 插入左子树:父节点bf–
  • 更新终止条件
    1. bf == 0:子树高度不变,停止更新
    2. bf == ±1:子树高度变化,继续向上回溯
    3. bf == ±2:触发旋转调整

3.3 关键代码实现

bool Insert(const std::pair<K, V>& kv) {// ... BST插入逻辑//...// 平衡因子更新循环while (parent) {if (cur == parent->_left) parent->_bf--;else parent->_bf++;if (parent->_bf == 0) break;else if (abs(parent->_bf) == 1) {cur = parent;parent = parent->_parent;} else if (abs(parent->_bf) == 2) {// 触发旋转if (parent->_bf == 2) {if (cur->_bf == 1) RotateL(parent);else RotateRL(parent);} else {if (cur->_bf == -1) RotateR(parent);else RotateLR(parent);}break;}}return true;
}

4. 旋转操作:从理论到代码

4.1 右单旋(LL型失衡)

触发条件
父节点bf = -2,左子节点bf = -1

代码实现

void RotateR(Node* parent) 
{Node* subL = parent->_left;Node* subLR = subL->_right;// 调整节点关系parent->_left = subLR;if (subLR) subLR->_parent = parent;subL->_right = parent;Node* ppNode = parent->_parent;parent->_parent = subL;// 处理父节点链接if (!ppNode) _root = subL;else if (ppNode->_left == parent) ppNode->_left = subL;else ppNode->_right = subL;subL->_parent = ppNode;// 更新平衡因子parent->_bf = subL->_bf = 0;
}

4.2 左单旋(RR型失衡)

触发条件
父节点bf = 2,右子节点bf = 1

代码实现

void RotateL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if(subRL)subRL->_parent = parent;Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (parentParent == nullptr){_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}parent->_bf = subR->_bf = 0;
}

5. 双旋场景深度剖析

5.1 左右双旋(LR型失衡)

场景分析
当插入节点导致父节点bf=-2,且左子节点bf=1时,需要先对左子树左旋,再对父节点右旋。

代码实现

void RotateLR(Node* parent) 
{Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(subL);RotateR(parent);// 平衡因子修正if (bf == 0) {parent->_bf = subL->_bf = 0;} else if (bf == -1) {parent->_bf = 1;subL->_bf = 0;} else {subL->_bf = -1;parent->_bf = 0;}subLR->_bf = 0;
}

5.2右左双旋(RL型失衡)

情况与左右双旋类似。

代码实现:

void RotateRL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 0){subR->_bf = 0;subRL->_bf = 0;parent->_bf = 0;}else if (bf == 1){subR->_bf = 0;subRL->_bf = 0;parent->_bf = -1;}else if (bf == -1){subR->_bf = 1;subRL->_bf = 0;parent->_bf = 0;}else{assert(false);}
}

6. 平衡检测与测试策略

6.1 递归验证算法

bool IsBalance() {return _IsBalanceTree(_root);
}int _Height(Node* root) {if (!root) return 0;return 1 + std::max(_Height(root->_left), _Height(root->_right));
}bool _IsBalanceTree(Node* root) {if (!root) return true;int leftH = _Height(root->_left);int rightH = _Height(root->_right);if (rightH - leftH != root->_bf) {std::cout << "平衡因子异常:" << root->_kv.first;return false;}return abs(leftH - rightH) < 2 && _IsBalanceTree(root->_left)&& _IsBalanceTree(root->_right);
}

7. 性能分析与工程实践

7.1 时间复杂度对比

操作BST最坏AVL树红黑树
插入O(N)O(logN)O(logN)
删除O(N)O(logN)O(logN)
查找O(N)O(logN)O(logN)

7.2 压力测试

void StressTest() {AVLTree<int, int> tree;const int N = 1000000;// 随机插入for (int i = 0; i < N; ++i) {tree.Insert({rand(), i});}assert(tree.IsBalance());// 查询性能测试auto start = clock();for (int i = 0; i < N; ++i) {tree.Find(rand());}cout << "Query Time:" << clock() - start << "ms";
}

8. 总结

AVL树的优势

  • 严格的平衡保证最优查询性能
  • 适合读多写少的场景

如有错误,恳请指正。

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

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

相关文章

跨平台游戏引擎 Axmol-2.6.0 发布

Axmol 2.6.0 版本是一个以错误修复和功能改进为主的次要LTS长期支持版本 &#x1f64f;感谢所有贡献者及财务赞助者&#xff1a;scorewarrior、peterkharitonov、duong、thienphuoc、bingsoo、asnagni、paulocoutinhox、DelinWorks 相对于2.5.0版本的重要变更&#xff1a; 通…

【Django Serializer】一篇文章详解 Django 序列化器

第一章 Django 序列化器概述 1.1 序列化器的定义 1.1.1 序列化与反序列化的概念 1. 序列化 想象你有一个装满各种物品&#xff08;数据对象&#xff09;的大箱子&#xff08;数据库&#xff09;&#xff0c;但是你要把这些物品通过一个狭窄的管道&#xff08;网络&#xff…

关于spring @Bean里调用其他产生bean的方法

背景 常常见到如下代码 Bean public TestBean testBean() {TestBean t new TestBean();System.out.println("testBean:" t);return t; }Bean public FooBean fooBean() {TestBean t testBean();System.out.println("这里看似是自己new的&#xff0c;但因为…

Level1.7列表

1.7_1列表&#xff08;索引切片&#xff09; #1.列表 students[Bob,Alice,Jim,Mike,Judy] print(students)#2.在列表&#xff08;添加不同数据类型&#xff0c;查看列表是否可以运行&#xff1f;是否为列表类型&#xff1f;&#xff09; students[Bob,Alice,Jim,Mike,Judy,123…

Python爬虫实战:研究Cola框架相关技术

一、Cola 框架概述 Cola 是一款基于 Python 的异步爬虫框架,专为高效抓取和处理大规模数据设计。它结合了 Scrapy 的强大功能和 asyncio 的异步性能优势,特别适合需要高并发处理的爬虫任务。 1.1 核心特性 异步 IO 支持:基于 asyncio 实现非阻塞 IO,大幅提高并发性能模块…

vue2中el-table 实现前端分页

一些接口不分页的数据列表&#xff0c;一次性返回大量数据会导致前端渲染卡顿&#xff0c;接口不做分页的情况下前端可以截取数据来做分页 以下是一个例子&#xff0c;被截取的列表和全量数据在同一个栈内存空间&#xff0c;所以如果有表格内的表单编辑&#xff0c;新的值也会事…

Python + moviepy:根据图片或数据高效生成视频全流程详解

前言 在数据可视化、自媒体内容生产、学术汇报等领域,我们常常需要将一组图片或一段变动的数据,自动合成为视频文件。这样不仅能提升内容表现力,也极大节省了人工操作时间。Python作为数据处理和自动化领域的王者,其`moviepy`库为我们提供了灵活高效的视频生成方案。本文将…

科技赋能,开启现代健康养生新潮流

在科技与生活深度融合的当下&#xff0c;健康养生也迎来了全新的打开方式。无需传统医学的介入&#xff0c;借助现代科学与智能设备&#xff0c;我们能以更高效、精准的方式守护健康。​ 饮食管理步入精准化时代。利用手机上的营养计算 APP&#xff0c;录入每日饮食&#xff0…

Ubuntu24.04 LTS安装java8、mysql8.0

在 Ubuntu 24.04 上安装 OpenJDK OpenJDK 包在 Ubuntu 24.04 的默认存储库中随时可用。 打开终端并运行以下 apt 命令: sudo apt update查看是否已经安装java java --version如果未安装会有提示&#xff0c;直接复制命令安装即可&#xff0c;默认版本&#xff1a; sudo apt in…

深度学习框架显存泄漏诊断手册(基于PyTorch的Memory Snapshot对比分析方法)

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;H卡级别算力&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生专属优惠。 一、显存泄漏&#xff1a;深度学习开发者的"隐形杀手" 在深度学习模型的训练与推…

Pytorch分布式训练,数据并行,单机多卡,多机多卡

分布式训练 所有代码可以见我github 仓库&#xff1a;https://github.com/xiejialong/ddp_learning.git 数据并行&#xff08;Data Parallelism&#xff0c;DP&#xff09; 跨多个gpu训练模型的最简单方法是使用 torch.nn.DataParallel. 在这种方法中&#xff0c;模型被复制…

【论文阅读】——D^3-Human: Dynamic Disentangled Digital Human from Monocular Vi

文章目录 摘要1 引言2 相关工作3 方法3.1 HmSDF 表示3.2 区域聚合3.3. 变形场3.4. 遮挡感知可微分渲染3.5 训练3.5.1 训练策略3.5.2 重建损失3.5.3 正则化限制 4. 实验4.1 定量评估4.2 定性评价4.3 消融研究4.4 应用程序 5 结论 摘要 我们介绍 D 3 D^{3} D3人&#xff0c;一种…

docker commit除了提交容器成镜像,还能搞什么之修改cmd命令

要让新镜像默认启动时执行 /usr/sbin/sshd -D&#xff0c;需在提交镜像时 ​​显式指定新的启动命令​​。 方法一&#xff1a;提交时通过 --change 覆盖 CMD docker commit --changeCMD ["/usr/sbin/sshd", "-D"] v2 project:v2 方法二&#xff1a;重…

为什么我输入对了密码,还是不能用 su 切换到 root?

“为什么我输入对了密码&#xff0c;还是不能用 su 切换到 root&#xff1f;” 其实这背后可能不是“密码错了”&#xff0c;而是系统不允许你用 su 切 root&#xff0c;即使密码对了。 &#x1f447; 以下是最常见的几个真正原因&#xff1a; ❌ 1. Root 用户没有设置密码&…

转移dp简单数学数论

1.转移dp问题 昨天的练习赛上有一个很好玩的起终点问题&#xff0c;第一时间给出bfs的写法。 但是写到后面发现不行&#xff0c;还得是的dp转移的写法才能完美的解决这道题目。 每个格子可以经过可以不经过&#xff0c;因此它的状态空间是2^&#xff08;n*m&#xff09;&…

IP查询基础介绍

IP 查询原理 IP 地址是网络设备唯一标识&#xff0c;IP 查询通过解析 IP 地址获取地理位置、运营商等信息。目前主流的 IPv4&#xff08;32 位&#xff09;与 IPv6&#xff08;128 位&#xff09;协议&#xff0c;前者理论提供约 43 亿地址&#xff0c;后者地址空间近乎无限。…

Linux命令简介

1 Linux系统的命令概述 在 Linux 操作系统中&#xff0c;凡是在字符操作界面中输入能够完成特定操作和任务的字符串都可以称为命令。严格来说&#xff0c;命令通常只代表实现某一类功能的指令或程序的名称。 1.1 Shell Linux 命令的执行必须依赖于 Shell 命令解释器。Shell …

WebRTC与RTSP|RTMP的技术对比:低延迟与稳定性如何决定音视频直播的未来

引言 音视频直播技术已经深刻影响了我们的生活方式&#xff0c;尤其是在教育、医疗、安防、娱乐等行业中&#xff0c;音视频技术成为了行业发展的重要推动力。近年来&#xff0c;WebRTC作为一种开源的实时通信技术&#xff0c;成为了音视频领域的重要选择&#xff0c;它使得浏览…

多通道振弦式数据采集仪MCU安装指南

设备介绍 数据采集仪 MCU集传统数据采集器与5G/4G,LoRa/RS485两种通信功能与一体的智能数据采集仪。该产品提供振弦、RS-485等的物理接口&#xff0c;能自动采集并存储多种自然资源、建筑、桥梁、城市管廊、大坝、隧道、水利、气象传感器的实时数据&#xff0c;利用现场采集的数…

Vue3 + Element Plus表格筛选样式设置

如果弹出框挂载在 body 下&#xff08;而非组件内部&#xff09;&#xff0c;scoped 样式无法生效&#xff0c;这时就需要使用全局样式。 强制全局样式 1、添加全局样式文件&#xff08;或在原有的文件中添加以下内容&#xff09; src/assets/global.scss /* 全局强制样式覆…