用红黑树封装实现map和set
目录
1、map和set的底层
2、map与set中的key关键值
3、红黑树迭代器的实现。
1、++操作
2、-- 操作
3、==和!=操作
4、在红黑树中封装迭代器
5、map和set对迭代器的封装
1、map
map中[]的重载
2、set
1、map和set的底层
map和set都是基于红黑树实现的。红黑树是一种自平衡的二叉搜索树,它保持着良好的平衡性能,插入、删除、查找的时间复杂度都是O(log n)。在C++ STL中,map和set都是使用红黑树作为底层数据结构来实现的。红黑树在前面文章模拟实现过,可以参考

rep_type通常是用来表示set容器内部红黑树的节点类型。在STL头文件中,通常会定义rep_type作为红黑树节点的类型,用于表示set容器和map容器内部的数据结构。
可以看到set和map的源代码中都使用了红黑树作为底层数据结构。
可以看到红黑树中的数据类型只有一个,
而在map和set中都有key值,也有数据类型,map的数据类型是键值对pair<const key,T>,set中的数据类型也是key。
2、map与set中的key关键值
那么我们该如何模拟实现呢?
🚀map传给红黑树的模板参数是pair键值对
🚀set传给红黑树的模板参数是key值
红黑树该如何判断key值来比较大小呢,这个时候我们需要使用仿函数的方法,因为红黑树比较节点只看key值。我们选择仿函数的方法:
map.h文件:
template<class K,class V>
class MYmap
{struct KeyofMap{const K& operator ()(const pair<K,V> &kv){return kv.first;}};
private:RBTree<K, pair<const K, V>, KeyofMap> _t;
};
set.h文件:
template<class T>
class Myset
{struct SetKeyofvalue{const T& operator()(const T& key){return key;}};
private:RBTree<T, const T, SetKeyofvalue> _t;
};
set存放的数据本身就是key,但是为了与红黑树结构:

以及map的结构统一,所以也需要实现一个。
3、红黑树迭代器的实现。
1、++操作
++操作也就是找到下一个比它大的值,那么就有两种可能:
1.右子树的最小值。
//如果右子树不为空,那么比这个元素大的下一个节点就是右子树的最小元素
//也就是右子树的最左节点
2.如果没有右子树,那么向上查找,直到找到一个节点是其父节点的左字数,该父节点就是符合条件的值。
Self& operator++(){//如果右子树不为空,那么比这个元素大的下一个节点就是右子树的最小元素//也就是右子树的最左节点if (_node->_right){Node* subrm = _node->_right;while (subrm->_left){subrm = subrm->_left;}_node = subrm;}//如果右子树为空,那么向上查找,直到找到一个节点是其父节点的左子树else{Node* cur = _node;Node* parent = cur->_parent;while (parent&& parent->_right == cur){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}
2、-- 操作
--操作也就是找到下一个比它小的值,那么就有两种可能:
1.左子树存在
//找出这个迭代器前面一个比它小的元素,如果左子树存在,那么就先找左边最大的节点
//也就是右子树的最右节点
2.左子树不存在
//如果左子树为空,那么向上查找,直到找到一个节点是其父节点的右子树
Self& operator --(){//找出这个迭代器前面一个比它小的元素,如果左子树存在,那么就先找左边最大的节点//也就是右子树的最右节点if (_node->_left){Node* sublmax = _node->_left;while (sublmax->_right){sublmax = sublmax->_right;}_node = sublmax;}//如果左子树为空,那么向上查找,直到找到一个节点是其父节点的右子树else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}
3、==和!=操作
//重载!=运算符bool operator!=(const Self& s){return _node != s._node;}//重载==运算符bool operator == (const Self & s){return _node == s._node;}
比较的内容是迭代器指向的节点是不是相同,不是比较节点的key值,同时也不需要修改,所以这里只需要const引用即可。
红黑树迭代器完整实现代码:
//红黑树迭代器
template<class T>
struct __RBTreeIterator
{typedef RBTreeNode<T> Node;typedef __RBTreeIterator<T> Self;Node* _node;__RBTreeIterator(Node* node):_node(node){}T& operator *(){return _node->_data;}T* operator ->(){return &_node->_data;}Self& operator++(){//如果右子树不为空,那么比这个元素大的下一个节点就是右子树的最小元素//也就是右子树的最左节点if (_node->_right){Node* subrm = _node->_right;while (subrm->_left){subrm = subrm->_left;}_node = subrm;}//如果右子树为空,那么向上查找,直到找到一个节点是其父节点的左子树else{Node* cur = _node;Node* parent = cur->_parent;while (parent&& parent->_right == cur){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}Self& operator --(){//找出这个迭代器前面一个比它小的元素,如果左子树存在,那么就先找左边最大的节点//也就是右子树的最右节点if (_node->_left){Node* sublmax = _node->_left;while (sublmax->_right){sublmax = sublmax->_right;}_node = sublmax;}//如果左子树为空,那么向上查找,直到找到一个节点是其父节点的右子树else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}//重载!=运算符bool operator!=(const Self& s){return _node != s._node;}//重载==运算符bool operator == (const Self & s){return _node == s._node;}};
4、在红黑树中封装迭代器
在红黑树中,起始节点begin()是最左节点
结束位置是空位置节点
本文采用上面的实现方法。
为了实现左闭右开,STL库采用的是end指向哨兵位头结点,最左边节点也和头相连。
template<class K,class T,class KeyofT>
class RBTree
{
public:typedef __RBTreeIterator<T> iterator;typedef RBTreeNode<T> Node;KeyofT kot;iterator begin(){Node* subleft = _root;while (subleft && subleft->_left){subleft = subleft->_left;}return iterator(subleft);}iterator end(){return iterator(nullptr);}
private:Node* _root=nullptr;
};
5、map和set对迭代器的封装
1、map
typedef typename RBTree<K, pair<const K, V>, KeyofMap>::iterator iterator;
这里要使用typename
当在模板中使用嵌套类型或依赖于模板参数的类型推导时,需要使用
typename关键字来告诉编译器这是一个类型而不是一个变量。这通常出现在模板中使用嵌套类型或依赖于模板参数的类型推导时。
map中[]的重载
V& operator[](const K& key){pair<iterator, bool> ret = Insert(make_pair(key, V()));return ret.first->second;}
map中的[]可以实现查找,修改,插入三个功能。
当使用
[]操作符访问map中的元素时,如果该键已经存在,则返回对应的值;
如果该键不存在,则会插入一个新的键值对,并返回一个默认构造的值。
在红黑树中也要对insert进行修改来匹配
我们来测试一下修改(更改value值):

#pragma once
#include"RBTree.h"template<class K,class V>
class MYmap
{struct KeyofMap{const K& operator ()(const pair<K,V> &kv){return kv.first;}};
public:typedef typename RBTree<K, pair<const K, V>, KeyofMap>::iterator iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}V& operator[](const K& key){pair<iterator, bool> ret = Insert(make_pair(key, V()));return ret.first->second;}pair<iterator,bool> Insert(const pair<const K, V>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, V>, KeyofMap> _t;
};
2、set
#pragma once
#include"RBTree.h"
template<class T>
class Myset
{struct SetKeyofvalue{const T& operator()(const T& key){return key;}};public:typedef typename RBTree<T,const T, SetKeyofvalue>::iterator iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}pair<iterator,bool> Insert(const T& key){return _t.Insert(key);}private:RBTree<T, const T, SetKeyofvalue> _t;
};
在C++的std::map和std::set容器中,元素的键值是不可更改的,这是因为这两个容器是基于红黑树实现的,红黑树的性质要求元素的键值在插入后不能被修改,否则会破坏红黑树的结构。
所以在实现时,map使用了
RBTree<K, pair<const K, V>, KeyofMap> _t;
set使用了
RBTree<T, const T, SetKeyofvalue> _t;
来保证key值不会被修改。
下面给出红黑树完整的插入函数:
pair<iterator,bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data, BLACK);Node* newnode = _root;//根的双亲为头结点return make_pair(iterator(newnode), true);}Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if(kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return make_pair(cur,false);}}cur = new Node(data, RED);Node* newnode = cur;if (kot(cur->_data) < kot(parent->_data)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;while (parent && parent->_color == RED){Node* grandparent = parent->_parent;if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_color == RED){grandparent->_color = RED;parent->_color = BLACK;uncle->_color = BLACK;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_left){RotateR(grandparent);parent->_color = BLACK;grandparent->_color = RED;}else{RotateL(parent);RotateR(grandparent);cur->_color = BLACK;grandparent->_color = RED;}break;}}else{Node* uncle = grandparent->_left;if (uncle && uncle->_color == RED){grandparent->_color = RED;parent->_color = BLACK;uncle->_color = BLACK;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);parent->_color = BLACK;grandparent->_color = RED;}else{RotateR(parent);RotateL(grandparent);cur->_color = BLACK;grandparent->_color = RED;}break;}}}_root->_color = BLACK;return make_pair(iterator(newnode),true);}
通过封装实现Map和Set,可以使用红黑树的特性来实现键值对的存储和查找,同时保持数据结构的平衡性和高效性。以上就是用红黑树封装实现map和set,当然这只是简单实现,对于更好地理解和使用这个容器比较有帮助。
相关文章:
用红黑树封装实现map和set
目录 1、map和set的底层 2、map与set中的key关键值 3、红黑树迭代器的实现。 1、操作 2、-- 操作 3、和!操作 4、在红黑树中封装迭代器 5、map和set对迭代器的封装 1、map map中[]的重载 2、set 1、map和set的底层 map和set都是基于红黑树实现的。红黑树是一种自平衡…...
【阿里云系列】-部署ACK集群的POD应用日志如何集成到日志服务(SLS)中
介绍 我们在实际部署应用到阿里云的ACK集群后,由于后期应用服务的持续维护诉求可能需要跟踪排查问题,此时就要具备将应用的历史日志存档便于后期排查问题 处理方式 为了解决以上的普遍需求,需要将ACK中的应用日志采集到SLS的Logstore中,然…...
Vue中给当前页面传递参数并重新加载,vue使用this.$router.push跳转页面,给跳转过去的页面传参不一致时重新加载
vue通过this.$router.push给url传参,改变url但是当前页面不会自动刷新 跳转页面代码 this.$router.push({name: allbusiness,query: {pw_id: item.id} });1.使用 watch 监听 $route 对象的变化,当路由发生变化时重新加载数据或执行其他操作。 2.利用路…...
【扩散模型(一)】综述:扩散模型在文本生成领域应用
一、论文信息 1 标题 Diffusion models in text generation: a survey 2 作者 Qiuhua Yi, Xiangfan Chen, Chenwei Zhang, Zehai Zhou, Linan Zhu, Xiangjie Kong 3 研究机构 1 College of Computer Science and Technology, Zhejiang University of Technology, HangZho…...
K8S Pod
基本概念 Pod是K8S中非常重要的概念之一,是整个K8S架构的基础和核心。Pod是K8S调度的最小单位,是一个不可拆分的独立个体,K8S将多个业务上相关联的容器(Docker容器)合并到一起,组合成一个Pod,这…...
反向传播(backward propagation,BP) python实现
BP算法就是反向传播,要输入的数据经过一个前向传播会得到一个输出,但是由于权重的原因,所以其输出会和你想要的输出有差距,这个时候就需要进行反向传播,利用梯度下降,对所有的权重进行更新,这样…...
简单算命脚本
效果展示 文件内容 main.py文件 import json import random import time# 别挂配置数据 gua_data_path "data.json"# 别卦数据 gua_data_map {} fake_delay 10# 读取别卦数据 def init_gua_data(json_path):with open(gua_data_path, r, encodingutf8) as fp:gl…...
Lua-掌握Lua语言基础1
Lua是一种轻量级的脚本语言,广泛应用于游戏开发、嵌入式系统和其他领域。下面是Lua语言基础的介绍: 数据类型:Lua支持基本的数据类型,包括nil、boolean、number、string和table。其中,table是一种关联数组,…...
python-0003-pycharm开发虚拟环境中的项目
前言 在虚拟环境中创建好了python项目,使用pycharm进行开发 打开项目 使用pycharm打开项目 设置虚拟环境的解释器 File–>Settings–>Project(项目名)–>Python Interpreter–>添加解释器–>添加已经存在的解释器–>选择虚拟环境的解释器 …...
修改 MySQL update_time 默认值的坑
由于按规范需要对 update_time 字段需要对它做默认值的设置 现在有一个原始的表是这样的 CREATE TABLE test_up (id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 主键id,update_time datetime default null COMMENT 操作时间,PRIMARY KEY (id) ) ENGINEInnoDB DEF…...
基于亚马逊云EC2+Docker搭建nextcloud私有化云盘
亚马逊云科技EC2云服务器(Elastic Compute Cloud)是亚马逊云科技AWS(Amazon Web Services)提供的一种云计算服务。EC2代表弹性计算云,它允许用户租用虚拟计算资源,包括CPU、内存、存储和网络带宽࿰…...
用try...catch进行判断
在写一些提交数据的判断上,有时候会写下面的ifelse的判断方法,少一点还好,多的话就很难受也不好看。 if(!that.driverObj.contrary){this.__utils.showToast(请先上传驾驶证副页图片);return false } if(!this.driverObj.start){this.__util…...
服务器遭遇挖矿病毒syst3md及其伪装者rcu-sched:原因、症状与解决方案
01 什么是挖矿病毒 挖矿病毒通常是恶意软件的一种,它会在受感染的系统上无授权地挖掘加密货币。关于"syst3md",是一种特定的挖矿病毒,它通过在受感染的Linux系统中执行一系列复杂操作来达到其目的。这些操作包括使用curl从网络下载…...
此机非彼机,工业计算机在工业行业的特殊地位
电子计算机,称为电脑。计算机是一种利用数字电子技术,根据一系列指令指示其自动执行任意算术或逻辑操作串行的设备。通用计算机因有能遵循被称为“程序”的一般操作集的能力而使得它们能够执行极其广泛的任务,以管理各种工厂和机器自动化工业…...
Python使用lxml解析XML格式化数据
Python使用lxml解析XML格式化数据 1. 效果图2. 源代码参考 方法一:无脑读取文件,遇到有关键词的行再去解析获取值 方法二:利用lxml等库,解析格式化数据,批量获取标签及其值 这篇博客介绍第2种办法,以菜鸟教…...
CDA-LevelⅡ【考题整理-带答案】
关于相关分析中应注意的问题,下面说法错误的是:B 如果两变量间的相关系数为0,则说明二者独立 。解释:只能说明两者不存在线性相关关系现通过参数估计得到一个一元线性回归模型为y3x4,在回归系数检验中下列说法错误的是…...
20240304 json可以包含复杂数组(数组里面套数组)
欣赏一下我的思维,它会以漫画,表格,文字。。。各种各样的形式呈现 对于问题1问题2 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。JSON本质上是一种文本…...
算法50:动态规划专练(力扣514题:自由之路-----4种写法)
题目: 力扣514 : 自由之路 . - 力扣(LeetCode) 题目的详细描述,直接打开力扣看就是了,下面说一下我对题目的理解: 事例1: 输入: ring "godding", key "gd" 输出: 4. 1. ring的第…...
重学SpringBoot3-集成Thymeleaf
更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-集成Thymeleaf 1. 添加Thymeleaf依赖2. 配置Thymeleaf属性(可选)3. 创建Thymeleaf模板4. 创建一个Controller5. 运行应用并访问页…...
【数据可视化】Echarts最常用图表
个人主页 : zxctscl 如有转载请先通知 文章目录 1. 前言2. 准备工作3. 柱状图3.1 绘制堆积柱状图3.2 绘制标准条形图3.3 绘制瀑布图 4. 折线图4.1 绘制堆积面积图和堆积折线图4.2 绘制阶梯图 5. 饼图5.1 绘制标准饼图5.2 绘制圆环图5.2 绘制嵌套饼图5.3 绘制南丁格尔…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...

