平衡二叉搜索树:AVL树和红黑树 📅 发布时间:2026/7/9 14:27:26 👁️ 浏览次数: AVL 树简介avl树是一种平衡二叉树通过“平衡因子”来实现左右两侧高度差的平衡只允许平衡因子取值为0、1、-1相对于红黑树avl树更接近“绝对平衡”但是对于旋转子树的处理要相对繁琐一些插入方法如果正好插入在较矮的子树那么久不需要旋转处理如果原来两棵子树同样高那么也不需要旋转处理如果插入在原来就较高的子树那么就需要进行旋转处理情况一根节点的左子树的左子树// 10 ----》 8// 8 b a 10// a c c ba是高度为h 1的子树其中包含了我们新插入的节点c子树是高度为h的子树b是高度为h的子树此时对于节点10他的平衡因子是-2需要进行旋转处理。左旋之后高度为h 1的a子树仍然在左边右子树的高度为h 1这样就实现了平衡8节点和10节点的平衡因子都被处理为了0情况二根节点的左子树的右子树// 10 ---- 10 ---- 8// 5 b 8 b 5 10// a 8 5 d a c d b// c d a c这里需要我们将情况一中的c子树进行拆分也就是上面例子中的以8为根节点的子树。a是高度为h的子树b、c是高度为h - 1的子树b是高度为h的子树情况二又可以根据8节点的平衡因子细分为三种情况无论哪种情况区分点在更新平衡因子在旋转上没有区别首先对8节点进行左单旋然后对10节点进行右单旋这样就完成了平衡随后根据前面说的新的节点的插入位置进行讨论更新8、5 10节点的平衡因子还有两种情况完全就是情况一、二的镜像版本没有任何区别这里不再过度赘述了avl树的验证从两个方面考虑一个是绝对高度是否满足左右子树差值不超过1另一个是平衡因子是否符合实际状况递归判断即可avl插入及验证的实现代码templateclassK,classVclassAVLNode{public:AVLNode(pairK,Vkv):kv(kv),bf(0),parent(nullptr),right(nullptr),left(nullptr){}pairK,Vkv;intbf;AVLNode*parent;AVLNode*right;AVLNode*left;};templateclassK,classVclassAVLTree{public:typedefAVLNodeK,VNode;boolinsert(pairK,Vkv){if(_rootnullptr){_rootnewNode(kv);returntrue;}Node*parentnullptr,*cur_root;while(cur){if(cur-kv.firstkv.first){parentcur;curcur-right;}elseif(cur-kv.firstkv.first){parentcur;curcur-left;}else{returnfalse;}}curnewNode(kv);if(cur-kv.firstparent-kv.first){parent-leftcur;}else{parent-rightcur;}cur-parentparent;while(parent){if(parent-leftcur){parent-bf--;}else{parent-bf;}if(parent-bf0){break;}elseif(parent-bf1||parent-bf-1){curparent;parentparent-parent;}elseif(parent-bf2||parent-bf-2){//旋转处理if(parent-bf-2cur-bf-1){RotateR(parent);}elseif(parent-bf-2cur-bf1){RotateLR(parent);}elseif(parent-bf2cur-bf1){RotateL(parent);}elseif(parent-bf2cur-bf-1){RotateRL(parent);}else{assert(false);}break;}else{assert(false);}}returntrue;}voidRotateR(Node*parent){Node*subLparent-left;Node*subLRsubL-right;Node*grandparentparent-parent;parent-parentsubL;parent-leftsubLR;if(subLR){subLR-parentparent;}subL-rightparent;if(parent_root){_rootsubL;subL-parentnullptr;}else{if(grandparent-leftparent){grandparent-leftsubL;}else{grandparent-rightsubL;}subL-parentgrandparent;}subL-bf0;parent-bf0;}voidRotateL(Node*parent){Node*subRparent-right;Node*subRLsubR-left;Node*grandparentparent-parent;subR-leftparent;parent-parentsubR;parent-rightsubRL;if(subRL){subRL-parentparent;}if(parent_root){_rootsubR;subR-parentnullptr;}else{if(grandparent-leftparent){grandparent-leftsubR;}else{grandparent-rightsubR;}subR-parentgrandparent;}subR-bf0;parent-bf0;}voidRotateLR(Node*parent){Node*subLparent-left;Node*subLRsubL-right;intbfsubLR-bf;RotateL(subL);RotateR(parent);if(bf0){subL-bf0;subLR-bf0;parent-bf0;}elseif(bf1){subL-bf-1;subLR-bf0;parent-bf0;}elseif(bf-1){subL-bf0;subLR-bf0;parent-bf-1;}else{assert(false);}}voidRotateRL(Node*parent){Node*subRparent-right;Node*subRLsubR-left;intbfsubRL-bf;RotateR(subR);RotateL(parent);if(bf0){subR-bf0;subRL-bf0;parent-bf0;}elseif(bf1){subR-bf0;subRL-bf0;parent-bf-1;}elseif(bf-1){subR-bf1;subRL-bf0;parent-bf0;}else{assert(false);}}voidinOrder(){_inOrder(_root);}booltest(){return_test(_root);}private:void_inOrder(Node*root){if(rootnullptr){return;}_inOrder(root-left);coutroot-kv.first root-kv.second root-bfendl;_inOrder(root-right);}int_height(Node*root){if(rootnullptr){return0;}intlh_height(root-left);intrh_height(root-right);returnlhrh?lh1:rh1;}bool_test(Node*root){if(rootnullptr){returntrue;}intdiff_height(root-right)-_height(root-left);if(abs(diff)1){coutbad height: root-kv.firstendl;}if(diff!root-bf){coutbad bf: root-kv.firstendl;returnfalse;}return_test(root-left)_test(root-right);}Node*_rootnullptr;};红黑树简介红黑树也是平衡二叉搜索树的一种实现比avl树的应用更广一些cstl中的map和set都是用的红黑树实现的虽然实现的没有avl树那么的“平衡”但是红黑树在最坏情况下dfs的时间复杂度也是2logN依然和avl树在同一数量级规则每个节点要么是红色要么是黑色根节点必须是黑色黑色节点可以连接但是红色节点不能相互链接而且红色节点的两个子节点如果有的话必须是黑色节点从根节点到任意一个叶子节点的路程中黑色节点的数目都必须是相等的插入方法由上面的规则不难推导出插入节点必须是红色节点否则会导致原来的红黑树第四条规则失效插入的话大类其实根据新插入节点父节点的颜色分为两种一种是原来的节点是黑色这种情况下插入即可另一种是插入节点的父节点是红色。在这种情况下根据叔叔节点的颜色又可以进行区分下面先规定以下三种子树(1)父子树parentp(2)爷爷子树grandparentg(3)叔叔子树uncleu (4)当前子树currentc包含新插入的节点这里和上面只以左右对称的两种情况的其中一种为例子进行演示(为了方便0表示红色1表示黑色):叔叔节点存在为红色// g1 ---- g0// p0 u0 p1 u1// c0 c0只需要变动父亲节点和叔叔节点颜色即可但是这里会出现连锁反应需要继续往上处理让现在的g子树成为下一次的c子树叔叔节点不存在或者叔叔节点为黑色这里又可以根据c节点和p节点的相对位置分为两种情况情况一c是p的左孩子// g1 ---- p1// p0 u1 c0 g0// c0 u1这种情况下进行一个右单旋即可随后修改g、p的颜色情况二c是p的右孩子// g1 ---- g1 ---- c1// p0 u1 c0 u1 p0 g0// c0 p0 u1这种情况需要先对c进行左单旋随后对g1进行右单旋红黑树的验证从两个方面一个是红色节点的连接情况有没有出现两个红色节点相连的情况另一个是各个节点的黑色节点的数目。依旧与avl树类似采取递归的方式处理红黑树的插入及验证实现代码enumColor{RED,BLACK};templateclassK,classVclassRBNode{public:RBNode(pairK,Vkv,enumColorcolRED):kv(kv),color(col){}pairK,Vkv;RBNode*parentnullptr;RBNode*leftnullptr;RBNode*rightnullptr;Color color;};templateclassK,classVclassRBTree{public:typedefRBNodeK,VNode;boolinsert(pairK,Vkv){if(_rootnullptr){_rootnewNode(kv,BLACK);returntrue;}Node*cur_root,*parentnullptr;while(cur){if(cur-kv.firstkv.first){parentcur;curcur-right;}elseif(cur-kv.firstkv.first){parentcur;curcur-left;}else{returnfalse;}}curnewNode(kv);if(kv.firstparent-kv.first){parent-rightcur;}else{parent-leftcur;}cur-parentparent;while(parentparent-colorRED){Node*grandparentparent-parent;if(grandparent-leftparent){Node*unclegrandparent-right;if(uncleuncle-colorRED){parent-coloruncle-colorBLACK;grandparent-colorRED;curgrandparent;parentparent-parent;}else{if(curparent-left){// g// p u// cRotateR(grandparent);parent-colorBLACK;grandparent-colorRED;break;}else{// g// p u// cRotateL(cur);RotateR(parent);cur-colorBLACK;grandparent-colorRED;break;}}}else{Node*unclegrandparent-left;if(uncleuncle-colorRED){parent-coloruncle-colorBLACK;grandparent-colorRED;curgrandparent;parentcur-parent;}else{if(parent-rightcur){// g// u p// cRotateL(grandparent);grandparent-colorRED;parent-colorBLACK;break;}else{// g// u p// cRotateR(parent);RotateL(grandparent);cur-colorBLACK;grandparent-colorRED;break;}}}}_root-colorBLACK;returntrue;}voidRotateR(Node*parent){Node*subLparent-left;Node*subLRsubL-right;Node*grandparentparent-parent;parent-parentsubL;subL-rightparent;parent-leftsubLR;if(subLR){subLR-parentparent;}if(parent_root){_rootsubL;subL-parentnullptr;}else{if(grandparent-leftparent){grandparent-leftsubL;}else{grandparent-rightsubL;}subL-parentgrandparent;}}voidRotateL(Node*parent){Node*subRparent-right;Node*subRLsubR-left;Node*grandparentparent-parent;parent-parentsubR;subR-leftparent;parent-rightsubRL;if(subRL){subRL-parentparent;}if(parent_root){_rootsubR;subR-parentnullptr;}else{if(grandparent-rightparent){grandparent-rightsubR;}else{grandparent-leftsubR;}subR-parentgrandparent;}}voidinOrder(){_inOrder(_root);}voidtest(){if(isBalance(_root)){cout红黑树经检查无误endl;}}private:void_inOrder(Node*root){if(rootnullptr){return;}_inOrder(root-left);coutroot-kv.first root-kv.secondendl;_inOrder(root-right);}boolisBalance(Node*root){if(rootnullptr){returntrue;}if(root-colorRED){returnfalse;}intref0;Node*curroot;while(cur){if(cur-colorBLACK){ref;}curcur-left;}coutrefddddendl;returncheck(root,0,ref);}boolcheck(Node*root,intblacknum,intref){if(rootnullptr){if(blacknum!ref){cout黑色节点数目错误 blacknum refendl;returnfalse;}returntrue;}if(root-colorREDroot-parent-colorRED){cout连续的红色节点endl;returnfalse;}if(root-colorBLACK){blacknum;}returncheck(root-left,blacknum,ref)check(root-right,blacknum,ref);}Node*_rootnullptr;};
信息安全毕业设计创新的项目选题怎么选 0 选题推荐 - 云计算篇 毕业设计是大家学习生涯的最重要的里程碑,它不仅是对四年所学知识的综合运用,更是展示个人技术能力和创新思维的重要过程。选择一个合适的毕业设计题目至关重要,它应该既能体现你的专业能力,又能满足实际应… 2026/7/8 21:52:30
app内手机防盗功能基本开发完成 我已经说完了,还是那个图片:主要用于静止情况下,手机被拿走这样的情况,类似于电子围栏。以后使用GPS都会非常方便了,因为我已经整理出了GPS类,调用都很方便。简单的开发应该没问题了。 2026/7/8 4:11:24
2026年革命:太空辐射环境测试如何重塑软件可靠性——软件测试从业者的专业解析 太空辐射测试的行业变革 2026年,随着商业航天与深空探测任务加速,软件测试面临前所未有的挑战:太空辐射环境成为影响系统可靠性的关键变量。高能粒子、宇宙射线及太阳辐射等极端条件,可能引发软件逻辑错误、数据损坏或硬件故… 2026/7/7 20:59:18
【首发狂欢】Windows 11 26H2 彻底封神!7大重磅新功能直击痛点(附在线升级 + ISO手动安装全教程) 作为微软 2026 年下半年的年度重磅更新,Windows 11 26H2终于正式揭开了神秘面纱!相较于过去一些“挤牙膏”式的维护,26H2 是一次真正直击亿万用户痛点的蜕变。更让人惊喜的是,对于 24H2 或 25H2 的用户而言,本次升级采… 2026/7/9 14:26:04
AD5593R与PIC18F96J94的嵌入式信号处理系统设计 1. AD5593R与PIC18F96J94的硬件协同设计 在嵌入式系统开发中,ADC(模数转换器)和DAC(数模转换器)的组合应用极为常见。AD5593R作为一款高度集成的混合信号IO芯片,与PIC18F96J94这款高性能8位MCU的搭配&#… 2026/7/9 14:24:04
Reddit外链:2026不封号拿Dofollow高权重指南 注册一个账号通常只需要耗费30秒钟。一个新账号要长成能发声的形态至少要熬过45天的静默期。前两周每天的在线时间最好严格控制在15到20分钟这个区间。头三天完全不需要敲击键盘,只需用鼠标翻阅前10个热门讨论。机器判定一个活跃用户的门槛,是每天超过5次… 2026/7/9 14:24:04
计算机毕业设计之基于ssm的中医理疗预约平台的设计与实现 本文介绍了一款使用SSM和Vue开发的中医理疗预约平台,及其设计与实现过程。根据软件工程对软件系统开发定制的规则和标准,详细的介绍了系统的分析与设计过程,并且详细的概括了系统的开发与测试过程。本文的管理系统使用了java进行系统的后端开… 2026/7/9 14:24:04
HarmonyOS WPS Open SDK:关闭回传 URI-FD 与 ResultData 解析实现 在 HarmonyOS 应用中集成 WPS Open SDK 后,OpenFileRequest 负责把沙箱内的文档交给 WPS 进程编辑。编辑结束后,最新文件内容往往落在 WPS 自身沙箱,而非调用方传入的原始路径。若业务需要在关窗后继续上传或持久化,必须在请求对象… 2026/7/9 14:22:03
全新窗口置顶方案:打造Mac高效工作新体验 全新窗口置顶方案:打造Mac高效工作新体验 【免费下载链接】Topit Pin any window to the top of your screen / 在Mac上将你的任何窗口强制置顶 项目地址: https://gitcode.com/gh_mirrors/to/Topit 还在为频繁切换窗口而烦恼吗?Topit是一款专为m… 2026/7/9 14:20:02
机器视觉与PLC集成:轮毂缺陷检测与字符识别误差控制在0.2mm内 机器视觉与PLC集成:轮毂缺陷检测与字符识别误差控制在0.2mm内的技术实现轮毂作为汽车关键零部件,其表面质量直接影响行车安全与美观。传统人工检测效率低且易漏检,而采用机器视觉与PLC集成方案可实现微米级精度检测。本文将深入解析高精度视觉… 2026/7/9 0:01:04
GBase 8a vs MySQL 8.0:ALTER TABLE语法与限制的5点关键差异对比 GBase 8a与MySQL 8.0:ALTER TABLE语法差异深度解析与实战指南1. 两种数据库的ALTER TABLE能力全景对比在数据库架构设计和运维过程中,表结构变更(DDL操作)是不可避免的需求。GBase 8a作为国产分析型数据库代表,与开源M… 2026/7/9 0:03:06
【大数据毕业设计】基于多源旅游数据的景区热度分析与推荐系统的设计与实现 基于 Django 的旅游偏好挖掘与景区推荐系统(源码+文档+远程调试,全bao定制等) 博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am… 2026/7/9 0:05:09
6个月转型AI工程师:实战路径与核心技能 1. 项目概述:6个月转型AI工程师的可行性路径在2023年大模型技术爆发的背景下,AI工程师岗位需求同比增长217%(LinkedIn数据)。不同于传统算法工程师需要3-5年培养周期,现代AI工程师更侧重工程化落地能力。我在硅谷科技公… 2026/7/7 11:26:57
TPAFE0808与PIC18F87K22的多通道信号采集方案 1. 项目背景与核心需求在工业自动化、医疗设备和科研仪器等领域,多通道信号采集与系统监测是基础且关键的技术需求。传统方案往往面临通道数量不足、信号调理复杂、系统集成度低等问题。TPAFE0808作为一款8通道模拟前端芯片,与PIC18F87K22微控制器的组合… 2026/7/8 20:15:17
STC3115与PIC18LF26K80构建高精度电池管理系统 1. STC3115与PIC18LF26K80在电池管理系统中的核心价值在现代电子设备中,电池管理系统(BMS)的重要性不亚于设备的核心处理器。STC3115作为一款高精度电池电量监测IC,与PIC18LF26K80微控制器的组合,构成了一个既能精确监控又能智能管理的完整解… 2026/7/8 14:25:08