跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

基于红黑树封装 C++ map/set:源码级实现与核心逻辑解析

红黑树是 C++ 标准库中 map 和 set 容器的底层数据结构。本文通过源码视角解析如何利用键提取器(仿函数)统一封装两种容器结构,解决 key/value 与纯 key 类型的通用性问题。重点阐述了迭代器在中序遍历下的 ++/-- 实现逻辑,以及通过 const 修饰防止 key 被修改的机制。同时涵盖了 insert 返回值优化以支持 operator[] 及统计功能,并说明了析构函数的后序遍历处理。

1951018925发布于 2026/3/24更新于 2026/10/1988 浏览
基于红黑树封装 C++ map/set:源码级实现与核心逻辑解析

容器 map 和 set 的底层实现均依赖于红黑树。本文深入探讨如何利用红黑树封装这两种标准容器,剖析其设计精妙之处与底层逻辑。

1. map/set 设计的巧妙之处

map 存储 key/value 对,set 仅存储 key。面对两种不同的参数类型,如何复用同一套红黑树结构?

直观方案是维护两棵独立的红黑树,但这会导致代码复用率极低且维护成本高昂。工程实践中,我们采用**键提取器(仿函数)**来统一处理:通过一个泛型接口提取 key,用同一颗红黑树同时支撑 map 和 set。 C++ 中的仿函数比 C 语言的函数指针更加灵活且类型安全。

文章配图

接下来,我们基于红黑树进行 map 和 set 的具体封装。

2. map 和 set 的实现

2.1 基本框架与模板通用化

map 是 key-value 结构,set 是 key 结构。为了共用底层红黑树,我们需要将参数通用化:

// 原红黑树可能定义为 K, V
// 现在统一为 T,T 可以是 pair<K,V> 或 K
template <typename T>
class RBTree {
    // ...
};

根据数据类型不同,分别编写对应的仿函数来控制底层获取 Key 的行为。

文章配图

文章配图

上层调用时传入仿函数对象,下层红黑树需新增一个模板参数接收该仿函数类型。

文章配图

2.2 Insert 操作

原本的红黑树插入 KV 结构,现在只需传入 data。data 的类型可能是 pair<K,V> 也可能是 Key。创建仿函数对象后,即可提取出用于比较的 Key。

文章配图

Insert 后续涉及 Key 比较大小,全部交由仿函数处理,形成回调机制。

文章配图

这样就实现了通用的插入逻辑。

文章配图

2.3 Find 操作

Find 同样依赖 Key 比较。由于 _data 类型不确定,依然需要仿函数来获取 Key 进行比较。

文章配图

map 和 set 直接复用红黑树的 Insert 和 Find 方法。

2.4 迭代器 Iterator

map 和 set 的迭代器均由红黑树迭代器封装而成。虽然源码中迭代器实现较为复杂(包含继承关系),但核心思想一致:通过重载运算符使迭代器行为类似指针。

难点在于 ++ 和 -- 的实现。红黑树作为二叉搜索树,中序遍历输出结果有序。因此,红黑树迭代器也是遵循中序遍历(左 -根 -右)的顺序。

  • begin: 返回中序遍历第一个结点(最左结点)。
  • end: 返回空结点(通常是最右结点的父节点或哨兵)。

迭代器的 ++ 返回中序下一个节点,-- 返回上一个节点。局部解决了这两个操作,全局顺序自然成立。虽然逻辑不复杂,但代码分支较多,属于典型的'代码难点'而非'逻辑难点'。

例如,当走到 10 节点时,说明当前子树的左、根已遍历完,接下来访问右子树。中序访问右子树,必须先访问其最左节点。若 15 没有最左节点(它本身就是右子树的最左节点),则 ++it 结果为 15。

文章配图

同理,若遍历到 18 节点,++it 即为右子树的最左节点 25。

文章配图

若右子树为空呢?以 15 为例,其右子树为空且自身已遍历,需向上寻找祖先。15 是 10 的右子树,说明 10 也已遍历完,继续向上找。若找到某个祖先是其左子树,则该祖先即为下一个节点;若一直找不到直到根,则结束。

文章配图

2.4.1 迭代器实现细节

文章配图

文章配图

红黑树内部使用迭代器:

文章配图

文章配图

上层(map 和 set)复用红黑树的迭代器。

注意模板未实例化时,取成员类型需加 typename 关键字。

文章配图

文章配图

文章配图

迭代器的 -- 和 ++ 完全对称,区别在于寻找左父亲还是右父亲,end 的前一个节点即为最右结点。

2.5 Key 不能被修改的问题

对于 set,key 是不可变的。如果迭代器允许修改 key,红黑树的平衡性和查找功能将失效。因此必须从源头禁止修改。

文章配图

最简单的做法是传递 const 引用:

文章配图

上层传递 const Key 给红黑树,K 被 const 修饰后无法修改。

文章配图

typedef 声明处也需加上 const,避免模板特化时的语义歧义报错。

对于 map,pair 中的 Key 同样不可变,处理方式一致。

文章配图

文章配图

2.6 修改 Find 返回值实现统计次数

将 Find 返回值改为 Iterator,配合其他逻辑可实现统计功能。

文章配图

文章配图

文章配图

2.7 修改 Insert 返回值实现 operator[]

map 和 set 的 operator[] 底层依赖 Insert 的返回值。

文章配图

文章配图

文章配图

newnode 保存新增结点 cur。因为插入过程涉及旋转和变色,向上更新后,最后的 cur 不一定是新增的原始结点。

文章配图

解决完 Insert,接下来实现 operator[]:

文章配图

逻辑如下:首先尝试插入 Key。如果插入失败(flag 为 false),说明 Key 已存在,it 指向已存在节点,返回 value;如果插入成功(flag 为 true),说明 Key 不存在,it 指向新增结点,返回 value。

外层对 value 执行 ++ 操作,即可轻松统计出现次数,无需额外复杂逻辑。

文章配图

文章配图

2.8 析构函数

map 和 set 的析构函数会调用红黑树的析构,因此无需单独编写。注意析构时应使用后序遍历,确保先销毁子节点再销毁父节点。

文章配图

文章配图

目录

  1. 1. map/set 设计的巧妙之处
  2. 2. map 和 set 的实现
  3. 2.1 基本框架与模板通用化
  4. 2.2 Insert 操作
  5. 2.3 Find 操作
  6. 2.4 迭代器 Iterator
  7. 2.4.1 迭代器实现细节
  8. 2.5 Key 不能被修改的问题
  9. 2.6 修改 Find 返回值实现统计次数
  10. 2.7 修改 Insert 返回值实现 operator[]
  11. 2.8 析构函数

更多推荐文章

查看全部
  • Layui 框架下 Unity WebGL Tab 切换黑屏解决方案
  • 前端核心面试八股文整理(含 JavaScript、Vue、React 等)
  • ROS 2 机器人物理属性配置与 Gazebo 仿真导入实战
  • 基于多种优化算法的物联网无人机基站部署与路径规划研究
  • Windows 环境 Git 安装与配置教程
  • 学生成绩综合统计分析系统设计与实现
  • 大模型理论基础:MoE 与 RAG 架构解析
  • Flutter 三方库 bones_ui 鸿蒙化适配指南
  • 校园社团活动管理平台设计:基于 SpringBoot 与 Vue 的实现
  • 从零搭建 Gitee 标准化脚本仓库:自动化运维脚本管理方案
  • 树莓派 4B 连接大疆 M300 无人机开发指南
  • Java 面向对象多态:向上转型与向下转型
  • 利用浏览器插件 Web Scraper 爬取知乎评论数据
  • VRCX 使用指南:VRChat 社交管理工具功能详解
  • JiuwenClaw AI 智能体实战:从安装到多端协同应用
  • 前端实战:基于 Vue3 实现无限滚动、懒加载与瀑布流模块及优化策略
  • AI 前端核心概念、技术栈与学习路径
  • 基于自适应卡尔曼滤波器的无人机追踪无人车 MATLAB 仿真
  • OpenClaw 大龙虾机器人本地部署与配置指南
  • 从 0 到 1 打造 RISC-V 智能家居中控:硬件 + 固件 + 通信全链路实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online