深入剖析:基于红黑树实现自定义 map 和 set 容器
🌟 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。🌟

在 C++ 标准模板库(STL)的大家庭里,map和set可是超级重要的关联容器成员呢😎!它们凭借红黑树这一强大的数据结构,实现了查找、插入和删除等操作的高效运行。
现在,就让我们一步步深入探索如何亲手基于红黑树打造自定义的map和set容器吧🧐!
目录
深入剖析:基于红黑树实现自定义 map 和 set 容器 🚀
一、红黑树基础结构与操作 🌳
1. 红黑树节点结构 📄
2. 红黑树类基本框架 📐
3. 左旋操作 🔄
4. 右旋操作 🔄
5. 插入修复 🔧
6. 插入操作 📥
7. 查找操作 🔍
8. 红黑树析构函数 🗑️
二、自定义 map 和 set 实现 🛠️
1. 自定义 set 实现 📚
(1)SetKeyOfT 仿函数 📐
2. 自定义 map 实现 🗺️
(1)MapKeyOfT 仿函数 📐
三、测试代码 🧪
一、红黑树基础结构与操作 🌳
1. 红黑树节点结构 📄
红黑树的节点结构包含节点颜色、父节点指针、左右子节点指针以及存储的数据。
- 实现思路:定义一个结构体来表示红黑树的节点,包含节点颜色、父节点指针、左右子节点指针和存储的数据。为方便后续操作,节点默认颜色设为红色,新插入节点通常为红色,有助于维持红黑树性质。
- 代码实现:
// 定义红黑树节点颜色
enum Colour {RED,BLACK
};// 红黑树节点结构体
template<class T>
class RBTreeNode {
public:RBTreeNode(const T& data) : _data(data),_left(nullptr),_right(nullptr),_parent(nullptr),_col(RED){}RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;T _data;
};
2. 红黑树类基本框架 📐
- 实现思路:定义红黑树类,包含根节点指针。提供插入、查找等基本操作函数声明,用于数据的插入、检索;同时定义左旋、右旋等内部操作函数声明,用于调整树结构,维持红黑树性质。
- 代码实现:
template<class K, class T, class KeyOfT>
class RBTree {
public:typedef RBTreeNode<T> Node;typedef _TreeIterator<T, T&, T*> iterator;typedef _TreeIterator<T, const T&, const T*> const_iterator;iterator begin();iterator end();const_iterator begin() const;const_iterator end() const;pair<Node*, bool> insert(const T& data);private:Node* _root = nullptr;void RotateL(Node* parent);void RotateR(Node* parent);void RotateRL(Node* parent);void RotateLR(Node* parent);
};
3. 左旋操作 🔄
实现步骤👇
-
保存关键节点指针:
- 保存
parent的右子节点subR和subR的左子节点subRL。
- 保存
-
调整
parent的右子节点:- 将
parent的右子节点更新为subRL。 - 如果
subRL不为空,将subRL的父节点指针指向parent。
- 将
-
调整
subR的左子节点:- 将
subR的左子节点更新为parent。 - 保存
parent的父节点parentParent。 - 将
parent的父节点指针指向subR。
- 将
-
更新根节点或父节点的子节点指针:
- 如果
parent是根节点(即parentParent为空),将subR设为新的根节点,并将subR的父节点指针置为空。 - 否则,根据
parent是parentParent的左子节点还是右子节点,更新parentParent的相应子节点指针为subR,并将subR的父节点指针指向parentParent。
- 如果
代码实现:
template<class K, class T, class KeyOfT>
void RBTree<K, T, KeyOfT>::RotateL(Node* parent) { Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL) {subRL->_parent = parent;}subR->_left = parent;Node* parentParent = parent->_parent;parent->_parent = subR;if (parentParent == nullptr) {_root = subR;subR->_parent = nullptr;}else {if (parentParent->_left == parent) {parentParent->_left = subR;}else {parentParent->_right = subR;}subR->_parent = parentParent;}
}
4. 右旋操作 🔄
- 实现思路:右旋操作以
parent为中心,交换其与左子节点subL位置,调整subLR指针,更新根或父节点指向维持平衡 - 代码实现:
template<class K, class T, class KeyOfT>
void RBTree<K, T, KeyOfT>::RotateR(Node* parent) { Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subL->_right;if (subLR) {subLR->_parent = parent;}subL->_right = parent;Node* parentParent = parent->_parent;parent->_parent = subL;if (parentParent == nullptr) {_root = subL;subL->_parent = nullptr;}else {if (parentParent->_left == parent) {parentParent->_left = subL;}else {parentParent->_right = subL;}subL->_parent = parentParent;}
}
5. 插入修复 🔧
- 实现思路:插入新节点后,红黑树的性质可能会被破坏,需要进行修复操作。修复操作主要根据新节点的父节点和叔节点的颜色进行分类处理,通过旋转和颜色调整来恢复红黑树的性质。
- 代码实现:
pair<Node*,bool> insert(const T& data)
{if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(_root, true);}Node* cur = _root;Node* parent = nullptr;KeyOfT kot;while (cur){parent = cur;if (kot(cur->_data) < kot(data)){cur = cur->_right;}else if (kot(cur->_data) > kot(data)){cur = cur->_left;}else{return make_pair(cur, false);}}//新增结点给红色cur = new Node(data);Node* newNode = cur;cur->_parent = parent;if (kot(parent->_data) < kot(cur->_data)){parent->_right = cur;}else{parent->_left = cur;}while (parent && parent->_col == RED){//找叔叔Node* grandfather = parent->_parent;Node* uncle = nullptr;if (parent == grandfather->_left){uncle = grandfather->_right;}else{uncle = grandfather->_left;}if (uncle && uncle->_col == RED)//满足规则一,父亲和叔叔变黑,爷爷变红{parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续向上更新cur = grandfather;parent = grandfather->_parent;}else //叔叔 不存在 或 存在且为黑{if (parent == grandfather->_left && cur == parent->_left)//右单旋{RotateR(grandfather);//变色parent->_col = BLACK;grandfather->_col = RED;}else if (parent == grandfather->_right && cur == parent->_right)//左单旋{RotateL(grandfather);//变色parent->_col = BLACK;grandfather->_col = RED;}else if (parent == grandfather->_left && cur == parent->_right)//折射,双旋{RotateLR(grandfather);//变色cur->_col = BLACK;grandfather->_col = RED;}else if (parent == grandfather->_right && cur == parent->_left)//折射,双旋{RotateRL(grandfather);//变色cur->_col = BLACK;grandfather->_col = RED;}}}_root->_col = BLACK;return make_pair(newNode, true);
}
6. 插入操作 📥
- 实现思路:首先找到合适的插入位置,创建新节点并插入到树中,然后调用插入修复函数来恢复红黑树的性质。
- 代码实现:
template<class K, class T, class KeyOfT>
pair<typename RBTree<K, T, KeyOfT>::Node*, bool> RBTree<K, T, KeyOfT>::insert(const T& data) {if (_root == nullptr) {_root = new Node(data);_root->_col = BLACK;return make_pair(_root, true);}Node* cur = _root;Node* parent = nullptr;KeyOfT kot;while (cur) {parent = cur;if (kot(cur->_data) < kot(data)) {cur = cur->_right;}else if (kot(cur->_data) > kot(data)) {cur = cur->_left;}else {return make_pair(cur, false);}}// 插入新节点并设置颜色cur = new Node(data);Node* newNode = cur;cur->_parent = parent;if (kot(parent->_data) < kot(cur->_data)) {parent->_right = cur;}else {parent->_left = cur;}while (parent && parent->_col == RED) {// 情况分类Node* grandfather = parent->_parent;Node* uncle = nullptr;if (parent == grandfather->_left) {uncle = grandfather->_right;}else {uncle = grandfather->_left;}if (uncle && uncle->_col == RED) { // 叔叔节点存在且为红色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 继续向上调整cur = grandfather;parent = grandfather->_parent;}else { // 叔叔节点不存在或为黑色if (parent == grandfather->_left && cur == parent->_left) { // 左左情况RotateR(grandfather);// 调整颜色parent->_col = BLACK;grandfather->_col = RED;}else if (parent == grandfather->_right && cur == parent->_right) { // 右右情况RotateL(grandfather);// 调整颜色parent->_col = BLACK;grandfather->_col = RED;}else if (parent == grandfather->_left && cur == parent->_right) { // 左右情况RotateLR(grandfather);// 调整颜色cur->_col = BLACK;grandfather->_col = RED;}else if (parent == grandfather->_right && cur == parent->_left) { // 右左情况RotateRL(grandfather);// 调整颜色cur->_col = BLACK;grandfather->_col = RED;}}}_root->_col = BLACK;return make_pair(newNode, true);
}
7. 查找操作 🔍
- 实现思路:从根节点开始,根据键的大小比较,递归地在左子树或右子树中查找目标节点。
- 代码实现:
template<class K, class T, class KeyOfT>
RBTreeNode<T>* RBTree<K, T, KeyOfT>::Find(const K& key) {RBTreeNode<T>* current = _root;KeyOfT kot;while (current) {if (key < kot(current->_data)) {current = current->_left;}else if (key > kot(current->_data)) {current = current->_right;}else {return current;}}return nullptr;
}
8. 红黑树析构函数 🗑️
- 实现思路:采用后序遍历的方式递归删除树中的所有节点,释放内存。
- 代码实现:
template<class K, class T, class KeyOfT>
RBTree<K, T, KeyOfT>::~RBTree() {auto destroyTree = [](RBTreeNode<T>* node) {if (node != nullptr) {destroyTree(node->left);destroyTree(node->right);delete node;}};destroyTree(_root);
}
二、自定义 map 和 set 实现 🛠️
1. 自定义 set 实现 📚
(1)SetKeyOfT 仿函数 📐
- 实现思路:由于
set中存储的元素就是键,因此仿函数直接返回元素本身。 - 代码实现:
namespace zdf {template<class K>class set {public:struct SetKeyOfT {const K& operator()(const K& key) {return key;}};// 定义迭代器类型typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;iterator begin() const {return _t.begin();}iterator end() const {return _t.end();}pair<iterator, bool> insert(const K& key) {return _t.insert(key);}private:RBTree<K, K, SetKeyOfT> _t;};
}
2. 自定义 map 实现 🗺️
(1)MapKeyOfT 仿函数 📐
- 实现思路:
map中存储的是键值对,仿函数从键值对中提取键。 - 代码实现:
namespace zdf {template<class K, class V>class map {struct MapKeyOfT {const K& operator()(const std::pair<K, V>& kv) {return kv.first;}};public:typedef typename RBTree<K, std::pair<const K, V>, MapKeyOfT>::iterator iterator;typedef typename RBTree<K, std::pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;iterator begin() {return _t.begin();}iterator end() {return _t.end();}V& operator[](const K& key) {std::pair<iterator, bool> ret = insert(std::make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const std::pair<K, V>& kv) {return _t.insert(kv);}private:RBTree<K, std::pair<const K, V>, MapKeyOfT> _t;};
}
三、测试代码 🧪
#include <iostream>int main() {// 测试setzdf::set<int> s;s.insert(3);s.insert(1);s.insert(2);// 测试mapzdf::map<int, std::string> m;m.insert({ 1, "one" });m.insert({ 2, "two" });m[3] = "three";std::cout << "Map value at key 3: " << m[3] << std::endl;return 0;
}

通过以上步骤,我们基于红黑树实现了自定义的map和set容器,每个函数的实现思路和代码都进行了详细讲解。这些实现展示了红黑树在关联容器中的重要应用,以及如何通过封装和扩展红黑树来实现高效的数据存储和操作。 🎉
欢迎关注我 👉【A charmer】
相关文章:
深入剖析:基于红黑树实现自定义 map 和 set 容器
🌟 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。🌟 在 C 标准模板库(STL)的大家庭里,map和set可是超级重要的关联容器成员呢😎&#x…...
20-R 绘图 - 饼图
R 绘图 - 饼图 R 语言提供来大量的库来实现绘图功能。 饼图,或称饼状图,是一个划分为几个扇形的圆形统计图表,用于描述量、频率或百分比之间的相对关系。 R 语言使用 pie() 函数来实现饼图,语法格式如下: pie(x, l…...
第438场周赛:判断操作后字符串中的数字是否相等、提取至多 K 个元素的最大总和、判断操作后字符串中的数字是否相等 Ⅱ、正方形上的点之间的最大距离
Q1、判断操作后字符串中的数字是否相等 1、题目描述 给你一个由数字组成的字符串 s 。重复执行以下操作,直到字符串恰好包含 两个 数字: 从第一个数字开始,对于 s 中的每一对连续数字,计算这两个数字的和 模 10。用计算得到的新…...
STM32F4 adc扫描模式采集实验
做adc采集的时候用扫描模式发现读数据时只能读到一个通道的数据,想显示其他几个通道的数据只能进行多次单个扫描,违背了扫描模式的本意,故用ai做了一个将扫描数据用dma储存在内存的adc三通道采集实验,若有巨佬发现有错望告知。 代…...
软考教材重点内容 信息安全工程师 第17章 网络安全应急响应技术原理与应用
17.1 网络安全应急响应概述 网络安全应急响应是针对潜在发生的网络安全事件而采取的网络安全措施。 17.1.1 网络安全应急响应概念 网络安全应急响应是指为应对网络安全事件,相关人员或组织机构对网络安全事件进行监测、预警、分析、响应和恢复等工作。 17.2.3 网络安…...
点击修改按钮图片显示有问题
问题可能出在表单数据的初始化上。在 ave-form.vue 中,我们需要处理一下从后端返回的图片数据,因为它们可能是 JSON 字符串格式。 vue:src/views/tools/fake-strategy/components/ave-form.vue// ... existing code ...Watch(value)watchValue(v: any) …...
Node.js技术原理分析系列——Node.js的perf_hooks模块作用和用法
Node.js 是一个开源的、跨平台的 JavaScript 运行时环境,它允许开发者在服务器端运行 JavaScript 代码。Node.js 是基于 Chrome V8 引擎构建的,专为高性能、高并发的网络应用而设计,广泛应用于构建服务器端应用程序、网络应用、命令行工具等。…...
大模型在术后认知功能障碍预测及临床方案制定中的应用研究
目录 一、引言 1.1 研究背景与意义 1.2 研究目的与方法 1.3 研究创新点 二、术后认知功能障碍概述 2.1 定义与表现 2.2 危害与影响 2.3 发病机制与相关因素 三、大模型技术原理与应用现状 3.1 大模型技术原理 3.2 大模型在医疗领域的应用 四、基于大模型的术后认知…...
用DeepSeek来帮助学习three.js加载3D太极模形
画一个平面的太极图是很容易,要实现3D的应该会很难 一、参考3D模形效果 看某网页看到一个效果,像一个3D太极球,觉得挺有趣,挺解压的,想进一步去了解下这是如何实现 效果: 链接地址: http://www.…...
【JavaEE进阶】Spring Boot配置文件
欢迎关注个人主页:逸狼 创造不易,可以点点赞吗 如有错误,欢迎指出~ 目录 SpringBoot配置⽂件 举例: 通过配置文件修改端口号 配置⽂件的格式 properties基本语法 读取配置⽂件 properties配置文件的缺点 yml配置⽂件 yml基本语法 yml和proper…...
学习通用多层次市场非理性因素以提升股票收益预测
“Learning Universal Multi-level Market Irrationality Factors to Improve Stock Return Forecasting” 论文地址:https://arxiv.org/pdf/2502.04737 Github地址:https://github.com/lIcIIl/UMI 摘要 深度学习技术与量化交易相结合,在股…...
【Godot4.3】基于绘图函数的矢量蒙版效果与UV换算
概述 在设计圆角容器时突发奇想: 将圆角矩形的每个顶点坐标除以对应圆角矩形所在Rect2的size,就得到了顶点对应的UV坐标。然后使用draw_colored_polygon,便可以做到用图片填充圆角矩形的效果。而且这种计算的效果就是图片随着其填充的图像缩…...
记一些工具(持续更新)
wireshark——网络抓包工具 mitmproxy ——利用中间人攻击进行https抓包的工具(需配合安装由此代理自己签发的根证书到客户机系统) Cloudflare—— 一个网站中间层,通过基于反向代理的内容分发网络(CDN),Cloudflare提供包括CDN、优化工具、安全、分析以…...
DeepSeek开源周Day1:FlashMLA引爆AI推理性能革命!
项目地址:GitHub - deepseek-ai/FlashMLA 开源日历:2025-02-24起 每日9AM(北京时间)更新,持续五天! 一、开源周震撼启幕 继上周预告后,DeepSeek于北京时间今晨9点准时开源「FlashMLA」,打响开源周五连…...
PCL 点云添加高斯噪声
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 在点云模型中将所有的点沿其法向量方向随机偏移一定距离,以此来得到点云实体的噪声点,偏移的幅度与点云尺度有关,偏移距离服从高斯分布,以此来获得高斯分布的噪声数据。 二、实现代码 // 标准文件 #include &l…...
通过恒定带宽服务器调度改进时间敏感网络(TSN)流量整形
论文标题 英文标题:Improving TSN Traffic Shaping with Constant Bandwidth Server Scheduling 中文标题:通过恒定带宽服务器调度改进时间敏感网络(TSN)流量整形 作者信息 作者:Benjamin van Seggelen 指导教师&am…...
软件测试高频面试题
以下是一些软件测试高频面试题: 基础概念类 HTTP和HTTPS的区别:HTTPS使用SSL/TLS协议对传输数据加密,HTTP没有加密;HTTPS可确保数据完整性,防止传输中被篡改,HTTP不保证;HTTP默认用80端口&…...
英语学习DAY5
内心旁白 关于我为什么从2月5号开的这个篇章现在才第五天这件事? 咳咳咳,容许我狡辩一下,我是有事去忙了,我真的很想每日学习英语(信我兄弟们)! 虽然英语学习对我来说真的很难,你…...
如何查看图片的原始格式
问题描述:请求接口的时候,图片base64接口报错,使用图片url请求正常 排查发现是图片格式的问题: 扩展名可能被篡改:如果文件损坏或扩展名被手动修改,实际格式可能与显示的不同,需用专业工具验证…...
Kronecker分解(K-FAC):让自然梯度在深度学习中飞起来
Kronecker分解(K-FAC):让自然梯度在深度学习中飞起来 在深度学习的优化中,自然梯度下降(Natural Gradient Descent)是一个强大的工具,它利用Fisher信息矩阵(FIM)调整梯度…...
赛前启航 | 三场重磅直播集结,予力微软 AI 开发者挑战赛!
随着微软 AI 开发者挑战赛的火热进行,赛前指导直播已成为众多参赛者获取技术干货、灵感碰撞和实战技巧的绝佳平台。继前两期的精彩呈现,第三、四、五期直播即将接连登场,为开发者们带来更加深入的 AI 技术剖析和项目实战指引。无论你是想进一…...
VMware安装Centos 9虚拟机+设置共享文件夹+远程登录
一、安装背景 工作需要安装一台CentOS-Stream-9的机器环境,所以一开始的安装准备工作有: vmware版本:VMware Workstation 16 镜像版本:CentOS-Stream-9-latest-x86_64-dvd1.iso (kernel-5.14.0) …...
【HarmonyOS Next】地图使用详解(一)
背景 这系列文章主要讲解鸿蒙地图的使用,当前可以免费使用,并提供了丰富的SDK给开发者去自定义控件开发。目前可以实现个性化显示地图、位置搜索和路径规划等功能,轻松完成地图构建工作。需要注意的是,现在测试只能使用实体手机去…...
【NLP 37、激活函数 ③ relu激活函数】
—— 25.2.23 ReLU广泛应用于卷积神经网络(CNN)和全连接网络,尤其在图像分类(如ImageNet)、语音识别等领域表现优异。其高效性和非线性特性使其成为深度学习默认激活函数的首选 一、定义与数学表达式 ReLU࿰…...
顶刊配图复现:Origin+DeepSeek完美协同
学习目标: (1)软件掌握熟练安装并配置Origin,掌握基础操作与核心功能。学会利用Origin进行多类型图表绘制及美化。掌握DeepSeek的数据清洗、统计分析与可视化方法。(2)设计能力理解顶刊图表的设计原则&…...
Fisher信息矩阵(Fisher Information Matrix, FIM)与自然梯度下降:机器学习中的优化利器
Fisher信息矩阵与自然梯度下降:机器学习中的优化利器 在机器学习尤其是深度学习中,优化模型参数是一个核心任务。我们通常依赖梯度下降(Gradient Descent)来调整参数,但普通的梯度下降有时会显得“笨拙”,…...
Scratch032(百发百中)
提示:知识回顾 1、排列克隆体的方法 2、复习“发送广播并等待”积木 3、“获取第几个字符”积木的使用 4、使用角色显示得分 前言 提示:中国射箭拥有悠久的历史,是最早进入教育体系的运动项目之一,君子六艺中“礼,乐,射,御,书,数”的射 ,就是指的射箭。这节课我带你…...
DeepSeek技术全景解析:架构创新与行业差异化竞争力
一、DeepSeek技术体系的核心突破 架构设计:效率与性能的双重革新 Multi-head Latent Attention (MLA):通过将注意力头维度与隐藏层解耦,实现显存占用降低30%的同时支持4096超长上下文窗口。深度优化的MoE架构:结合256个路由专家…...
开课倒计时 | 3月1-2日,DeepSeek时代下的可观测性(Observability)认证培训
前言: 随着DeepSeek等前沿AI技术的广泛应用,企业对可观测性的需求日益增长。DeepSeek作为一款强大的AI模型,已经在多个领域展现出其卓越的性能。然而,随着技术复杂性的增加,如何有效监控和优化这些系统成为关键挑战。…...
相似性搜索(2)
在本篇中,我们通过播客相似性搜索为例,进一步研究基于chroma 的相似性搜索: 参考: https://www.kaggle.com/code/switkowski/building-a-podcast-recommendation-engine/notebook 数据集来源: https://www.kaggle.…...
