新闻详情

新闻详情

首页 / 资讯中心 / 详情

map和set基于红黑树的实现

发布时间:2026/9/25 19:28:58来源:尧图网络
map和set基于红黑树的实现
从这里可以看出来set和map都是在红黑树的基础上对传入参数做出改变实现的一个时key一个是pairkey valueset传第二个参数是为了兼容map的pair同时传入第三个是为了在插入时从map中取出key进行排序把红黑树通用的拓扑结构颜色、三个指针抽到基类把和业务相关的数据 Value 放在派生类树平衡旋转等底层操作使用基类指针实现做到平衡逻辑与存储的数据类型解耦一套红黑树可以支持 set、map 不同 Value把不变的逻辑封装成父类减少代码在生成时的冗余。通过下图对框架的分析我们可以看到源码中rb_tree⽤了⼀个巧妙的泛型思想实现rb_tree是实现key的搜索场景还是key/value的搜索场景不是直接写死的⽽是由第⼆个模板参数Value决定_rb_tree_node中存储的数据类型。• set实例化rb_tree时第⼆个模板参数给的是keymap实例化rb_tree时第⼆个模板参数给的是pairconst key, T这样⼀颗红⿊树既可以实现key搜索场景的set也可以实现key/value搜索场景的map。• 要注意⼀下源码⾥⾯模板参数是⽤T代表value⽽内部写的value_type不是我们我们⽇常key/value场景中说的value源码中的value_type反⽽是红⿊树结点中存储的真实的数据的类型。• rb_tree第⼆个模板参数Value已经控制了红⿊树结点中存储的数据类型为什么还要传第⼀个模板参数Key呢尤其是set两个模板参数是⼀样的这是很多同学这时的⼀个疑问。要注意的是对于map和setfind/erase时的函数参数都是Key所以第⼀个模板参数是传给find/erase等函数做形参的类型的。对于set⽽⾔两个参数是⼀样的但是对于map⽽⾔就完全不⼀样了map insert的是pair对象但是find和ease的是Key对象。• 吐槽⼀下这⾥源码命名⻛格⽐较乱set模板参数⽤的Key命名map⽤的是Key和T命名⽽rb_tree⽤的⼜是Key和Value可⻅⼤佬有时写代码也不规范乱弹琴。2. 模拟实现map和set核心框架通过第二个模板参数的不同在__rb_tree_node的结构上让红黑树生成的类不同。2. 模拟实现map和set2.1 实现出复⽤红⿊树的框架并⽀持insert参考源码框架map和set复⽤之前我们实现的红⿊树。• 我们这⾥相⽐源码调整⼀下key参数就⽤Kvalue参数就⽤V红⿊树中的数据类型我们使⽤T。• 其次因为RBTree实现了泛型不知道T参数导致是K还是pairK, V那么insert内部进⾏插⼊逻辑⽐较时就没办法进⾏⽐较因为pair的默认⽀持的是key和value⼀起参与⽐较我们需要时的任何时候只⽐较key所以我们在map和set层分别实现⼀个MapKeyOfT和SetKeyOfT的仿函数传给RBTree的KeyOfT然后RBTree中通过KeyOfT仿函数取出T类型对象中的key再进⾏⽐较具体细节参考如下代码实现。b_tree 作为通用泛型容器无法预知存储的元素 T 是 K 还是 pairK,V。如果直接使用 T 进行比较pair 默认比较会同时比较 key 和 value而 map 只允许 key 参与比较。所以我们提供 KeyOfT 萃取仿函数set 用 identity 直接返回元素本身map 用 select1st 提取 pair 的 first。rb_tree 内部依靠这个仿函数拿到 key只使用 key 完成查找、比较、判重实现一套 rb_tree 同时支撑 set 与 map。解决比较判断的问题pair内部的比较逻辑是first和second同时参与比较与map的比较逻辑不符合我们用仿函数来去出pair的key进行比较# 总结对比1. 运算符重载**绑定在类型上一个类型一套固定规则不能随便换**2. 仿函数独立的策略类型**可插拔、可带成员状态、编译期确定逻辑、不止能比较还能做萃取 / 转换**## 面试精简背诵适配你的红黑树问题仿函数不仅仅用来实现比较。1. **策略可插拔**作为模板参数同一套 rb_tree 可以传入不同仿函数切换萃取规则、排序规则不用重写容器代码2. **可以保存状态**普通函数和运算符重载无法携带成员变量3. 它是类型支持模板实例化编译期内联运行时开销很小4. 仿函数不局限于返回 bool 做大小比较像select1st萃取仿函数可以用来提取数据这也是我们 rb_tree 区分 map/set 的核心5. STL 容器、算法的扩展机制都是基于仿函数设计。map和set分别传入自己的仿函数用自己的比较逻辑通过在RBtree生成不同的两个类实现不同的比较逻辑iterator实现思路分析iterator实现的⼤框架跟list的iterator思路是⼀致的⽤⼀个类型封装结点的指针再通过重载运算符实现迭代器像指针⼀样访问的⾏为。• 这⾥的难点是operator和operator--的实现。之前使⽤部分我们分析了map和set的迭代器⾛的是中序遍历左⼦树-根结点-右⼦树那么begin()会返回中序第⼀个结点的iterator也就是10所在结点的迭代器。• 迭代器的核⼼逻辑就是不看全局只看局部只考虑当前中序局部要访问的下⼀个结点。• 迭代器时如果it指向的结点的右⼦树不为空代表当前结点已经访问完了要访问下⼀个结点是右⼦树的中序第⼀个⼀棵树中序第⼀个是最左结点所以直接找右⼦树的最左结点即可。• 迭代器时如果it指向的结点的右⼦树空代表当前结点已经访问完了且当前结点所在的⼦树也访问完了要访问的下⼀个结点在当前结点的祖先⾥⾯所以要沿着当前结点到根的祖先路径向上找。• 如果当前结点是⽗亲的左根据中序左⼦树-根结点-右⼦树那么下⼀个访问的结点就是当前结点的⽗亲如下图it指向2525右为空25是30的左所以下⼀个访问的结点就是30。• 如果当前结点是⽗亲的右根据中序左⼦树-根结点-右⼦树当前当前结点所在的⼦树访问完了当前结点所在⽗亲的⼦树也访问完了那么下⼀个访问的需要继续往根的祖先中去找直到找到孩⼦是⽗亲左的那个祖先就是中序要问题的下⼀个结点。如下图it指向1515右为空15是10的右15所在⼦树话访问完了10所在⼦树也访问完了继续往上找10是18的左那么下⼀个访问的结点就是18。• end()如何表⽰呢如下图当it指向50时it时50是40的右40是30的右30是18的右18到根没有⽗亲没有找到孩⼦是⽗亲左的那个祖先这是⽗亲为空了那我们就把it中的结点指针置为nullptr我们⽤nullptr去充当end。需要注意的是stl源码空红⿊树增加了⼀个哨兵位头结点做为end()这哨兵位头结点和根互为⽗亲左指向最左结点右指向最右结点。相⽐我们⽤nullptr作为end()差别不⼤他能实现的我们也能实现。只是--end()判断到结点时空特殊处理⼀下让迭代器结点指向最右结点。具体参考迭代器--实现。• 迭代器--的实现跟的思路完全类似逻辑正好反过来即可因为他访问顺序是右⼦树-根结点-左⼦树具体参考下⾯代码实现。• set的iterator也不⽀持修改我们把set的第⼆个模板参数改成const K即可 RBTreeK,const K, SetKeyOfT _t;• map的iterator不⽀持修改key但是可以修改value我们把map的第⼆个模板参数pair的第⼀个参数改成const K即可 RBTreeK, pairconst K, V, MapKeyOfT _t;• ⽀持完整的迭代器还有很多细节需要修改具体参考下⾯题的代码。2.3 map⽀持[]首先iterator还是复用PBtree的迭代器这里的迭代器和我之前写的list的迭代器类似通过传入的模板参数不同生成不同的类核心迭代器的实现的思路就是返回当前节点的右节点的最左节点如果没有右节点就向上找当前节点是父亲左节点的节点并返回该父亲节点--的时候多了一层特殊处理就是 根节点--的时候返回的是最右边的节点这样也就支持了逆序引入root最大用处就是处理空的情况
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

单片机物联网|毕设答辩|毕业设计项目|基于51单片机的交通控制系统设计 2026/9/25 20:10:10

单片机物联网|毕设答辩|毕业设计项目|基于51单片机的交通控制系统设计

标题:基于51单片机的交通控制系统设计文档介绍:第1章 绪论1.1研究背景与意义我国城市化进程持续加快,城市人口密度骤增,机动车保有量呈爆发式增长,统计显示,到2023年底,全国机动车保有量超4.3亿…

阅读更多 →
MindSpore大模型训练评估体系搭建与性能优化实战指南 2026/9/25 20:10:04

MindSpore大模型训练评估体系搭建与性能优化实战指南

做了一年多大模型训练的调优,我的结论是:评估体系不是为了“证明模型没问题”,而是为了“告诉你怎么改”。这篇文章就围绕 MindSpore 环境下做大模型训练时最绕不开的两个话题——评估体系和性能优化——把我在 70B 级模型、多卡集群上踩过的…

阅读更多 →
知识图谱也会有脏数据?用 pySHACL 给 RDF 加一道数据校验 2026/9/25 20:10:04

知识图谱也会有脏数据?用 pySHACL 给 RDF 加一道数据校验

做 MySQL 的时候,我们对“数据校验”其实很熟悉。 比如用户表: CREATE TABLE user (id BIGINT PRIMARY KEY,username VARCHAR(64) NOT NULL,age INT );这里已经偷偷规定了很多规则: id 必须有 username 不能为空 username 最长 64 age 必须是…

阅读更多 →
Claude Code 模板实战:从 CLAUDE.md 到 slash 命令的完整指南 2026/9/25 20:10:04

Claude Code 模板实战:从 CLAUDE.md 到 slash 命令的完整指南

Claude Code 用了一段时间之后,我的结论很明确:这工具的判断力足够强,但真正拉开效率差距的,从来不是模型本身,而是你喂给它的“规矩”。同一个任务,裸奔的 Claude Code 和带着一套成熟模板的 Claude Code&…

阅读更多 →
Atlas 300V 24G推理加速卡部署YOLO模型全攻略 2026/9/25 20:09:57

Atlas 300V 24G推理加速卡部署YOLO模型全攻略

1. 先说清楚:Atlas 300V 24G到底算不算“运算加速卡”1.1 这个争议是怎么来的先说说那个热搜词:“atlas 300v 24g 是运算加速卡吗”。我猜会搜这个问题的人,多半是在服务器选型或者边缘设备改造时遇到了两个方向的建议。有人说它能做AI加速&a…

阅读更多 →
【装备篇01】基于BP神经网络的雷达干扰系统综合效能评估模型 2026/9/25 20:09:57

【装备篇01】基于BP神经网络的雷达干扰系统综合效能评估模型

目录 一、应用场景:电子战雷达干扰装备效能评估 二、指标体系设计 三、案例描述 四、关键代码与解析 4.1 数据定义 4.2 网络结构与初始化 4.3 核心训练循环(带详细注释) 4.4 预测与评估 4.5 训练损失曲线 五、典型运行结果 六、国…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉