C++实现简单的平衡二叉树平衡因子计算 _ 深度差逻辑【源码】

风杰酱_1106

风杰酱_1106

2026-04-11

845人浏览

原创

平衡因子是左子树高度减右子树高度的有符号差值,即bf = height(left) - height(right),取值仅为-1、0、1;空节点高度定义为-1,以确保叶子节点高度为0,且旋转后仅需更新x、y两个节点的高度和平衡因子。

c++实现简单的平衡二叉树平衡因子计算 _ 深度差逻辑【源码】

平衡因子怎么算?别直接用 abs(left_height - right_height)

平衡因子不是“左右子树高度差的绝对值”,而是左子树高度减右子树高度的**有符号差值**。AVL 树定义里明确要求每个节点的平衡因子只能是 -1、0 或 1,bf = height(left) - height(right)。如果写成 abs(...),就丢失了方向信息,后续判断哪边高、该做哪种旋转(LL / LR / RR / RL)时会完全失效。

常见错误现象:insert 后树看起来“不歪”,但实际插入新节点后触发了错误旋转,甚至破坏 BST 性质——根本原因是平衡因子符号错了,导致旋转类型误判。

  • 必须单独维护每个节点的 height 字段(或每次递归计算),不能只靠 bf 反推
  • 更新平衡因子必须在更新高度之后:先递归算出左右子树高度,再算当前 bf,最后更新当前节点 height = max(left_height, right_height) + 1
  • 若用递归求高度(不缓存),时间复杂度退化为 O(n) 每次,务必避免在 getBalanceFactor() 里重复调用两次 getHeight()

getHeight() 必须处理空指针,且返回 -1 还是 0?

标准 AVL 实现中,空节点(nullptr)高度定义为 -1,这样叶子节点高度才是 0(两个子树都为空 → max(-1, -1) + 1 = 0)。这个约定直接影响 bf 计算结果是否符合定义。

错误示例:把空节点高度设为 0,则叶子节点高度变成 1,所有 bf 值整体偏移,插入单个节点后根节点 bf 就会是 1 而非 0,后续逻辑全乱。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • 统一用 getHeight(nullptr) → -1
  • 对应地,getNodeHeight(Node* n) 应写成:
    int getNodeHeight(Node* n) { return n ? n->height : -1; }
  • 千万别在 getNodeHeight 里对 n 做递归调用——那是 updateHeight() 的事

插入后只更新路径上节点的 height 和 bf,别全量重算

AVL 插入是自底向上修复的,只有从插入点到根的路径上的节点高度可能变化,其余子树不受影响。逐层回溯时,每层只需:

  • 用左右子节点当前 height 更新本节点 height
  • 立即计算本节点新 bf = getNodeHeight(n->left) - getNodeHeight(n->right)
  • 若 bf 超出 [-1,1],才触发旋转;旋转后要重新设置参与旋转的 2~3 个节点的 height 和 bf

性能关键点:没被访问的子树,其 height 字段保持原值,不碰;bf 不存储也行,但每次判断旋转前必须实时算——因为旋转会改变局部结构,缓存的 bf 很快过期。

旋转后哪些节点的 height 和 bf 必须重置?

以 rightRotate(y) 为例(y 是失衡节点,x 是 y 的左孩子):旋转后,x 成为新子树根,y 变为其右孩子。此时只有 x 和 y 的 height 和 bf 可能变;x 的原右子树(即 y 的左子树)和 y 的右子树未参与结构调整,高度不变。

  • 必须重算 x->height 和 y->height(顺序不能反:先 y 再 x,因为 x 的高度依赖 y 的新高度)
  • 接着重算 x->bf 和 y->bf —— 注意此时它们的子节点指针已更新,必须用新拓扑
  • 其他节点(如 x 的左子树根、y 的右子树根)的 height 和 bf 完全不用动

容易被忽略的是:旋转函数内部不负责更新祖父节点的指针或高度,那是插入函数回溯时的工作。很多初学者在 rightRotate 里强行改 parent->left/right 或调用 updateHeight(parent),反而破坏调用栈逻辑。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

2026.04.23

359

31

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5747

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2468

6

空指针异常处理
空指针异常处理

本专题整合了空指针异常解决方法,阅读专题下面的文章了解更多详细内容。

2025.11.16

179

10

OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

2026.10.16

20

10

OpenJDK怎么配置Java开发环境
OpenJDK怎么配置Java开发环境

怎样用OpenJDK搭建开发环境?本专题介绍版本选择、下载安装、环境变量配置和编译运行验证,帮助你理清JDK的作用及基本配置流程,并通过简单程序检查环境是否可用,为后续项目开发做好准备。

2026.10.16

0

10

OpenJDK怎么部署Java应用
OpenJDK怎么部署Java应用

Java项目开发完成后,怎样部署到目标环境并正常运行?本专题介绍OpenJDK应用部署流程,涵盖运行环境准备、版本兼容检查、应用打包、启动参数配置和日志查看,帮助你理清部署前后的操作顺序,减少环境差异造成的运行问题。

2026.10.16

0

10

Revel框架模板渲染与表单验证
Revel框架模板渲染与表单验证

本专题围绕Revel框架视图层开发,介绍模板语法、变量输出、布局复用、表单提交、参数绑定与验证规则,帮助开发者完成安全规范的页面交互。

2026.10.16

0

15

Revel框架MVC路由与控制器
Revel框架MVC路由与控制器

本专题聚焦Revel框架MVC核心机制,讲解路由定义、控制器Action、参数绑定、请求响应和反向路由,并结合常见场景梳理接口请求处理流程。

2026.10.16

0

15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习