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 最重要的查…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...