c++ - 模拟实现set、map
文章目录
- 前言
- 一、set模拟实现
- 二、map模拟实现
前言
在C++标准库中,std::set 和 std::map都是非常常用的容器,它们提供了基于键值对的存储和快速查找能力。然而,关于它们的底层实现,C++标准并没有强制规定具体的数据结构,只是规定了它们的行为特性(如唯一性、有序性等)。不过,大多数C++标准库实现(如GCC的libstdc++和Clang的libc++)都采用了红黑树(Red-Black> Tree)作为std::set和std::map的底层数据结构。
下面都是基于红黑树实现的set和map。
一、set模拟实现
当前的红黑树需要这三个类型参数(键值、数据,通过数据求key的仿函数),这是为了map也能够复用,但是set只传入一个数据,所以采用这样的方式:<K, const K,Setfunc< K >>,因为set中的数据是不能被修改的所以在第二个类型中加上const
1、基本框架
//获取红黑树key的函数
template <class K>
struct Setfunc
{K operator()(const K& val){return val;}
};template <class K, class KeyOfValue = Setfunc<K>>
class set
{
public://红黑树typedef RBTree<K, const K, KeyOfValue> RB;private://红黑树RB _rbset;};
2、迭代器
这里的迭代器直接复用红黑树的迭代器。
/*
第一 K类型是作为键值给删除,查找等需要键值的接口使用的
第二 const K是作为数据,给插入等接口使用
第三 KeyOfValue是仿函数,是给红黑树将数据类型转化为key使用,如插入时使用
*/
//迭代器
typedef typename RBTree<K,const K, KeyOfValue>::Iterator iterator;
typedef typename RBTree<K, const K, KeyOfValue>::ConstIterator cosnt_iterator;//迭代器
iterator begin()
{return _rbset.Begin();
}iterator end()
{return _rbset.End();
}cosnt_iterator begin() const
{return _rbset.Begin();
}cosnt_iterator end() const
{return _rbset.End();
}
3、插入、删除、查找、清空
以上接口均复用红黑树接口
//插入
pair<bool, iterator> insert(const K & val)
{return _rbset.Insert(val);
}//删除
bool erase(const K& key)
{return _rbset.Erase(key);
}//查找
iterator find(const K& key)
{return _rbset.Find(key);
}//清空
bool clear()
{_rbset.Clear();
}
4、拷贝构造和赋值重载
(1)拷贝构造:
遍历需要拷贝的对象,再插入到新的对象里。
set(const set<K, KeyOfValue> & p)
{//遍历set,重新插入set<K, KeyOfValue>::cosnt_iterator it = p.begin();while (it != p.end()){insert(*it);++it;}
};
(2)赋值重载:
比拷贝构造多一步,就是在插入前需要清空。
set<K, KeyOfValue>& operator=(const set<K, KeyOfValue>& p)
{//清空当前setclear();//遍历set,重新插入set<K, KeyOfValue>::cosnt_iterator it = p.begin();while (it != p.end()){insert(*it);++it;}
}
5、测试
void test_set()
{set<int> _s;//插入for (int i = 0; i < 10; i++){_s.insert(i);}cout << "s1: ";set<int> s1 = _s; //拷贝构造//迭代器遍历set<int>::iterator it1 = s1.begin();while (it1 != s1.end()){cout << *it1 << " ";++it1;}cout << endl;cout << "s2: ";set<int> s2;s2 = s1; //赋值//删除s2.erase(1);s2.erase(5);s2.erase(4);s2.erase(8);//迭代器遍历set<int>::iterator it2 = s2.begin();while (it2 != s2.end()){cout << *it2 << " ";++it2;}cout << endl;
}

6、总代码
//获取红黑树key的函数
template <class K>
struct Setfunc
{K operator()(const K& val){return val;}
};template <class K, class KeyOfValue = Setfunc<K>>
class set
{
public://红黑树typedef RBTree<K, const K, KeyOfValue> RB;/*第一 K类型是作为键值给删除,查找等需要键值的接口使用的第二 const K是作为数据,给插入等接口使用第三 KeyOfValue是仿函数,是给红黑树将数据类型转化为key使用,如插入时使用*///迭代器typedef typename RBTree<K,const K, KeyOfValue>::Iterator iterator;typedef typename RBTree<K, const K, KeyOfValue>::ConstIterator cosnt_iterator;//构造set() {};set(const set<K, KeyOfValue> & p) {//遍历set,重新插入set<K, KeyOfValue>::cosnt_iterator it = p.begin();while (it != p.end()){insert(*it);++it;}};set<K, KeyOfValue>& operator=(const set<K, KeyOfValue>& p){//清空当前setclear();//遍历set,重新插入set<K, KeyOfValue>::cosnt_iterator it = p.begin();while (it != p.end()){insert(*it);++it;}return *this;}//析构~set() {};//迭代器iterator begin(){return _rbset.Begin();}iterator end(){return _rbset.End();}cosnt_iterator begin() const{return _rbset.Begin();}cosnt_iterator end() const{return _rbset.End();}//插入pair<bool, iterator> insert(const K & val){return _rbset.Insert(val);}//删除bool erase(const K& key){return _rbset.Erase(key);}//查找iterator find(const K& key){return _rbset.Find(key);}//清空void clear(){_rbset.Clear();}private://红黑树RB _rbset;
};
二、map模拟实现
map给红黑树传的类型为:<K, pair<const K, V, KeyOfValue> ,K类型用于删除、查找等,pair<const K, V,>作为数据插入,KeyOfValue取pair<const K, V,>中的K类型,又因为键值不能修改所以pair<const K, V,>中的K加上const修饰。
1、基础框架
//获取 pair<K,V>中的key
template <class K,class V>
struct Mapfunc
{K operator()(const pair<K,V>& val){return val.first;}
};template <class K, class V, class KeyOfValue = Mapfunc<K,V>>
class map
{
public://重命名typedef RBTree<K, pair<const K, V>, KeyOfValue> RB;
private://红黑树RB _rbmap;
};
2、迭代器
依旧是复用红黑树迭代器即可。
typedef typename RB::Iterator iterator;
typedef typename RB::ConstIterator const_iterator;iterator begin()
{return _rbmap.Begin();
}iterator end()
{return _rbmap.End();
}const_iterator begin() const
{return _rbmap.Begin();
}const_iterator end()const
{return _rbmap.End();
}
3、插入、删除、查找、清空
依旧是复用红黑树接口即可。
//插入
pair<bool,iterator> insert(const pair<K, V>& val)
{return _rbmap.Insert(val);
}//删除
bool erase(const K& key)
{return _rbmap.Erase(key);
}//查找
iterator find(const K& key)
{return _rbmap.Find(key);
}//清空
void clear()
{_rbmap.Clear();
}
4、重载[ ]
当key不存在时,重载[ ]就会用key进行插入操作并返回插入后key对应数据的引用(此时key对应数据是用其默认构造进行初始化的),当key存在时,返回key对应数据的引用。
//重载[]
V& operator[](const K& key)
{pair<bool, iterator> ret = insert(make_pair(key, V()));return ret.second->second;
}
5、拷贝构造和赋值构造
(1)遍历需要拷贝的对象并将其数据插入当前对象即可。
map(const map<K,V, KeyOfValue> & p)
{map<K, V, KeyOfValue>::const_iterator it = p.begin();while (it != p.end()){insert(*it);++it;}
};
(2)先清空再遍历插入当前对象即可。
map<K, V, KeyOfValue>& operator=(const map<K, V, KeyOfValue>& p)
{clear();map<K, V, KeyOfValue>::const_iterator it = p.begin();while (it != p.end()){insert(*it);++it;}return *this;
}
6、测试
void test_map()
{//默认构造map<int, int> m;//插入for(int i = 1; i < 10; i++)m.insert({ i,i });//迭代器遍历cout << "m1:";//拷贝构造map<int, int> m1 = m;map<int, int>::iterator it1 = m1.begin();while (it1 != m1.end()){cout << it1->second << " ";++it1;}cout << endl;cout << "m2:";//赋值map<int, int> m2;m2 = m;//删除m2.erase(1);m2.erase(2);//使用[]m2[3] = 100;m2[4] = 100;map<int, int>::iterator it2 = m2.begin();while (it2 != m2.end()){cout << it2->second << " ";++it2;}}

7、总代码
template <class K,class V>
struct Mapfunc
{K operator()(const pair<K,V>& val){return val.first;}
};
template <class K, class V, class KeyOfValue = Mapfunc<K,V>>
class map
{
public:typedef RBTree<K, pair<const K, V>, KeyOfValue> RB;typedef typename RB::Iterator iterator;typedef typename RB::ConstIterator const_iterator;map() {};~map() {};map(const map<K,V, KeyOfValue> & p) {map<K, V, KeyOfValue>::const_iterator it = p.begin();while (it != p.end()){insert(*it);++it;}};map<K, V, KeyOfValue>& operator=(const map<K, V, KeyOfValue>& p){clear();map<K, V, KeyOfValue>::const_iterator it = p.begin();while (it != p.end()){insert(*it);++it;}return *this;}//迭代器iterator begin(){return _rbmap.Begin();}iterator end(){return _rbmap.End();}const_iterator begin() const {return _rbmap.Begin();}const_iterator end()const {return _rbmap.End();}//插入pair<bool,iterator> insert(const pair<K, V>& val){return _rbmap.Insert(val);}//删除bool erase(const K& key){return _rbmap.Erase(key);}//查找iterator find(const K& key){return _rbmap.Find(key);}//重载[]V& operator[](const K& key){pair<bool, iterator> ret = insert(make_pair(key, V()));return ret.second->second;}//清空void clear(){_rbmap.Clear();}private:RB _rbmap;
};
相关文章:
c++ - 模拟实现set、map
文章目录 前言一、set模拟实现二、map模拟实现 前言 在C标准库中,std::set 和 std::map都是非常常用的容器,它们提供了基于键值对的存储和快速查找能力。然而,关于它们的底层实现,C标准并没有强制规定具体的数据结构,只…...
计算机网络-PIM协议基础概念
一、PIM基础概念 组播网络回顾: 组播网络从网络结构上大体可以分为三个部分: 源端网络:将组播源产生的组播数据发送至组播网络。 组播转发网络:形成无环的组播转发路径,该转发路径也被称为组播分发树(Multi…...
优化PyCharm:让IDE响应速度飞起来
优化PyCharm:让IDE响应速度飞起来 PyCharm,作为一款功能强大的集成开发环境(IDE),在提供丰富功能的同时,有时也会出现响应慢的问题。这不仅影响开发效率,还可能打击开发者的积极性。本文将详细…...
对象转化为String,String转化为对象
title: 对象转化为string,string转化为对象 date: 2024-08-02 11:50:40 tags: javascript const obj { uname:haha, age:18,gender:女} //将对象转换成string JSON.stringify(obj) //取成一个对象,将字符串传化为对象 JSON.parse(obj)常用领域在localst…...
SolverLearner:提升大模型在高度归纳推理的复杂任务性能,使其能够在较少的人为干预下自主学习和适应
SolverLearner:提升大模型在高度归纳推理的复杂任务性能,使其能够在较少的人为干预下自主学习和适应 提出背景归纳推理(Inductive Reasoning)演绎推理(Deductive Reasoning)反事实推理(Counterf…...
PHP智能问诊导诊平台-计算机毕业设计源码75056
摘 要 智能问诊导诊平台作为一种智能化医疗服务工具,利用PHP语言开发,旨在为用户提供便捷的在线问诊和导诊服务。该平台集成了智能算法和医疗数据,实现了智能化的病情诊断和治疗建议,帮助用户更快速地获取医疗信息和建议。用户可…...
数据结构初阶(c语言)-排序算法
数据结构初阶我们需要了解掌握的几种排序算法(除了直接选择排序,这个原因我们后面介绍的时候会解释)如下: 其中的堆排序与冒泡排序我们在之前的文章中已经详细介绍过并对堆排序进行了一定的复杂度分析,所以这里我们不再过多介绍。 一&#x…...
网络云相册实现--nodejs后端+vue3前端
目录 主页面 功能简介 系统简介 api 数据库表结构 代码目录 运行命令 主要代码 server apis.js encry.js mysql.js upload.js client3 index.js 完整代码 主页面 功能简介 多用户系统,用户可以在系统中注册、登录及管理自己的账号、相册及照片。 每…...
【JS】Object.defineProperty与Proxy
一、Object.defineProperty 这里只是简单描述,具体请看另一篇文章:Object.defineProperty。 Object.defineProperty 是 JavaScript 中用于定义或修改对象属性的功能强大的方法。它可以精确地控制属性的行为,如是否可枚举、可配置、可写等。…...
《计算机网络》(第8版)第8章 互联网上的音频/视频服务 复习笔记
第 8 章 互联网上的音频/视频服务 一、概述 1 多媒体信息的特点 多媒体信息(包括声音和图像信息)最主要的两个特点如下: (1)多媒体信息的信息量往往很大; (2)在传输多媒体数据时&a…...
linux进程控制——进程替换——exec函数接口
前言: 本节内容进入linux进程控制板块的最后一个知识点——进程替换。 通过本板块的学习, 我们了解了进程的基本控制方法——进程创建, 进程退出, 进程终止, 进程替换。 进程控制章节和上一节进程概念板块都是在谈进程…...
Apache解析漏洞~CVE-2017-15715漏洞分析
Apache解析漏洞 漏洞原理 # Apache HTTPD 支持一个文件拥有多个后缀,并为不同后缀执行不同的指令。比如如下配置文件: AddType text/html .html AddLanguage zh-CN .cn# 其给 .html 后缀增加了 media-type ,值为 text/html ;给 …...
Xilinx管脚验证流程及常见问题
1 流程 1.1 新建I/O Planning Project I/O Planning Project中可以不需要RTL的top层.v代码,仅图形化界面即可配置管脚约束XDC文件的生成: Create I/O Ports: 导出XDC文件和自动生成的top_interface.v文件: 1.2 新建test Project …...
格雷厄姆的《聪明的投资者》被誉为“投资圣经”
本杰明格雷厄姆的《聪明的投资者》(The Intelligent Investor: A Book of Practical Counsel)是投资领域的一部经典之作,被誉为“投资圣经”。以下是对该书的详细解析: 一、书籍基本信息 书名:《聪明的投资者》&…...
TypeScript声明文件
TypeScript声明文件 在JavaScript的生态系统中,随着项目的复杂度和规模不断增加,开发者对于类型安全和代码质量的追求也日益增长。TypeScript,作为JavaScript的一个超集,通过添加静态类型检查和ES6等新特性支持,极大地…...
.NET_WPF_使用Livecharts数据绑定图表
相关概念 LiveCharts 是一个开源的图表库,适用于多种 .NET 平台,包括 WPF、UWP、WinForms 等。LiveCharts 通过数据绑定与 MVVM 模式兼容,使得视图模型可以直接控制图表的显示,无需直接操作 UI 元素。这使得代码更加模块化&#x…...
一句JS代码,实现随机颜色的生成
今天我们只用 一句JS代码,实现随机颜色的生成,首先看一下效果: 每次刷新浏览器背景颜色都不一样 实现此效果的JS函数 : let randomColor () > ...: 定义一个箭头函数randomColor,用于生成一个随机颜色。 Math.ra…...
校园抢课助手【7】-抢课接口限流
在上一节中,该接口已经接受过风控的处理,过滤掉了机器人脚本请求,剩下都是人为的下单请求。为了防止用户短时间内高频率点击抢课链接,海量请求造成服务器过载,这里使用接口限流算法。 先介绍下几种常用的接口限流策略…...
char类型和int类型
一、char类型 在Java中,char(字符)类型用于表示单个字符,它是基本数据类型之一。以下是关于Java中char类型的一些重要信息: 表示方式: char类型用于存储Unicode字符,占用16位(即2个字…...
C++参悟:stl中的比较最大最小操作
stl中的比较最大最小操作 一、概述二、最小值1. min2. min_element 三、最大值1. max2. max_element 四、混合1. minmax2. minmax_element 一、概述 记录这里C11中常用的最小值和最大值的比较函数,最好的参考资料其实就是 https://zh.cppreference.com 最重要的查…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...
