map和set的封装

目录

一、红黑树的改造

1.1节点的定义

二、红黑树的迭代器

2.1用节点封装迭代器

2.2迭代器的实现

2.3map和set的迭代器

三、insert的返回值

3.1insert返回值的用处

3.2operator[ ]的实现

四、key不能修改的问题


 

  • 封装map和set一般分为六步:

  1. 封装map和set

  2. 普通迭代器

  3. const迭代器

  4. insert的返回值

  5. map operator[ ]

  6. key不能修改问题

一、红黑树的改造

1.1节点的定义

map和set的底层都是用一棵红黑树来封装的,但是map和set节点里面存储的值不一样,map存储的是<key,pair<key,value>>,set存储的<key,key>,多存储一个key是因为查找节点的需要(查找节点一般是按照key去查找的),所以统一用data来表示map和set存储的数据,再在map和set内部定义一个仿函数,通过传参使用函数对象来获得data中具体的key值

RBTreeNode(const T& data):_data(data), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED)
{}//set的keyoft
struct KeyOfT
{const K& operator()(const K& key){return key;}
};//map的keyofT
struct  KeyOfT
{const K& operator()(const pair<K, V>& kv){return kv.first;}
};

二、红黑树的迭代器

2.1用节点封装迭代器

用节点去封装迭代器,关键在于实现operator++和operator--。STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后, 可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位 置,end()放在最大节点(最右侧节点)的下一个位置,那么下个位置是在哪里呢?实际上,end()是一个指向根节点的虚拟头结点。实现过程中,为了方便实现,定义end()的位置是nullptr;

template<class T, class Ptr, class Ref>
struct _Treeiterator
{typedef RBTreeNode<T> Node;Node* _node;typedef _Treeiterator<T, Ptr, Ref> Self;typedef _Treeiterator<T, T*, T&> iterator;_Treeiterator (Node* node):_node(node){}_Treeiterator(const iterator& it):_node(it._node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data);}Self& operator++(){//右树不为空-->找右树的最左节点if (_node->_right){Node* leftnode = _node->_right;while (leftnode->_left){leftnode = leftnode->_left;}_node = leftnode;}//右树为空else{Node* cur = _node;Node* parent = cur->_parent;while (parent){if (cur == parent->_left){break;}else{cur = cur->_parent;parent = parent->_parent;}}_node = parent;}return *this;}Self& operator--(){//左树不为空-->找左树的最右节点if (_node->_left){Node* rightnode = _node->_left;while (rightnode->_right){rightnode = rightnode->_right;}_node = rightnode;}//左树为空else{Node* cur = _node;Node* parent = cur->_parent;while (parent&& cur == parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
  • 实现operator++:红黑树是按照中序遍历的方式访问节点数据的,当前根节点访问完就要去访问当前根节点的右子树
  1. 因此++的重载分为两种情况:当右子树不为空,说明右子树的数据没有访问过,那就去访问右子树的最左节点;当右子树为空,说明该根节点形成的子树已经被访问完了,那么就要向上继续访问;
  2. 向上访问也分为两种情况:如果当前根节点是它父亲节点的左孩子,说明下一个访问的就是父亲节点,直接将_node更新为parent;如果当前根节点是它父亲节点的右孩子,说明以它的父亲节点为根节点的子树也访问完了,那么就向上继续访问,直到某个位置的节点是它父亲节点的左孩子,或者已经到达整棵树的根节点,再把_node更新为parent;
  • 实现operator--:--实现的过程是++的逆过程,判断的时候判断左子树即可

2.2迭代器的实现

typedef _Treeiterator<T, T*,T&> iterator;
typedef _Treeiterator<T, const T*,const T&> const_iterator;iterator begin()
{Node* cur = _root;Node* leftmin = _root->_left;while (leftmin->_left){leftmin = leftmin->_left;}return iterator(leftmin);
}iterator end()
{return iterator(nullptr);
}const_iterator begin() const
{Node* cur = _root;Node* leftmin = _root->_left;while (leftmin->_left){leftmin = leftmin->_left;}return const_iterator(leftmin);
}const_iterator end() const
{return const_iterator(nullptr);
}

2.3map和set的迭代器

  • map的迭代器

  • set的迭代器

 

因为set中只有key,key永远是不可修改的 ,所以set的普通迭代器是用const迭代器去实现的,实现迭代器的时候也只需要实现const迭代器

三、insert的返回值

3.1insert返回值的用处

 

  • 在map的operator[ ]中可以看到,operator[ ]的返回值是借助insert实现的,这就决定了insert的返回值必须是一个pair,并且是一个pair<iterator, bool>。要实现map的operator[ ]就要修改insert的返回值。
  • 插入一个节点,如果key已经存在,就返回pair<该节点(存储该key)的迭代器, false>;如果key不存在,插入成功就返回pair<新插入节点的迭代器, true>。
  • 插入节点的value默认给缺省值,外部没传值给value就默认使用缺省值。
  • 以下是三种不同情况下,insert的返回值

初始化根节点

 key已经存在

 

插入新节点且key不存在 

 

3.2operator[ ]的实现

实际上,set中根本不需要实现operator[ ],但是由于map和set都是用相同的一颗红黑树去封装的,红黑树insert的返回值改变也会影响set的插入,因为map有需求,而set就是一个陪跑。

  • map的operator[ ]

 operator[ ]返回的是insert返回值中节点迭代器中的value值

  • set的insert

 

set的插入的返回值因为insert返回值的改变复杂了许多。原因是,在set内部,Insert返回的pair内的迭代器类型只能是一个const迭代器,但是在Insert内部调用树的insert返回的pair内的是一个普通迭代器,是完全不同的两个类型,所以必须用普通迭代器去构造const迭代器,才能保证Insert返回的pair内的是一个正确的const迭代器。

map内部Insert返回的pair内的迭代器类型可以是一个普通迭代器,因此不存在返回值类型不匹配的问题

那么如何才能用普通迭代器去构造const迭代器呢?这里有一个非常巧妙的思路。

这里的_Treeiterator(const iterator& it)包含两层意思:当需要创建的是一个const迭代器对象,这里的_Treeiterator(const iterator& it)就是一个构造函数;当需要创建的是一个普通迭代器,这里的_Treeiterator(const iterator& it)就是一个普通迭代器的拷贝构造函数。

为了实现这一点,我们多定义了一个模板显示实例化后一定为普通迭代器的iterator,目的就是为了保证_Treeiterator(const iterator& it)函数的实现。

四、key不能修改的问题

map和set的key不管在什么情况下都是不能修改的,如何实现这一点呢?

  • 因为set的迭代器本质上都为const迭代器,注定了set的key是不能修改的;
  • 要想让map的key值不能修改,只需要在key前面用const修饰就可以实现,即pair<const key, value>

 

源代码:mymap_myset_8_16/mymap_myset_8_16 · 阿赭/C++学习 - 码云 - 开源中国 (gitee.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/415092.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MFC生成dll的区别

主要分三种&#xff1a; A. 动态链接库(dll) B.具有导出项的(dll)动态链接库 C.MFC动态链接库 对比项目&#xff1a;可以根据需要选择哪种dll方便 添加自定义导出功能Demo 1. 添加导出实现接口&#xff1a; A. 导出需要具有&#xff1a;__declspec(dllexport) B. 按照C语言…

Javascript LeeCode选题(汉诺塔求解)

LeeCode选题 汉诺塔递归求解move移动函数hanoi函数main方法测试代码&#xff1a;代码实现 汉诺塔递归求解 汉诺塔介绍&#xff1a; 汉诺塔的的图形&#xff08;从上到下1&#xff0c;2&#xff0c;3个&#xff09;实现&#xff1a; 这里我们可以看到因为必须要将第n个移动到…

Spring中基于redis stream 的消息队列实现方法

本文主要介绍了消息队列的概念性质和应用场景&#xff0c;介绍了kafka、rabbitMq常用消息队列中间件的应用模型及消息队列的实现方式&#xff0c;并实战了在Spring中基于redis stream 的消息队列实现方法。 一、消息队列 消息队列是一种进程间通信或者同一个进程中不同线程间的…

uni-app 获取当前位置的经纬度以及地址信息

文章目录 uni.getLocation(objc)获取经纬度和地址调试结果问题 uni-app 获取当前位置的经纬度以及地址信息 uni.getLocation(objc) uni-app官方文档定位API: uni.getLocation(OBJECT) uni.getLocation({type: wgs84,success: function (res) {console.log(当前位置的经度&…

【系统架构设计】嵌入式系统设计(1)

【系统架构设计】嵌入式系统设计&#xff08;1&#xff09; 嵌入式系统概论嵌入式系统的组成硬件嵌入式处理器总线存储器I/O 设备与接口 软件 嵌入式开发平台与调试环境交叉平台开发环境交叉编译环境调试 嵌入式系统概论 嵌入性、专用性、计算机系统是嵌入式系统的三个基本的核…

【话题讨论】VS Code:倍增编程动力,实现效率飞跃

目录 引言 一、详情介绍 功能特点 使用场景 提高工作效率 二、效率对比 2.1 高度可定制性与丰富的插件生态 2.2 智能的代码补全与导航 2.3 内置的调试器与版本控制集成 2.4 轻量级与跨平台 2.5 选择合适工具的重要性 2.6 实际案例或数据展示 三、未来趋势 3.1 编…

能见度监测站—实时监测道路能见度情况

型号&#xff1a;TH-NJD10】能见度监测站是一种专门用于自动观测和存储气象观测数据的设备&#xff0c;它通过高科技手段实时监测大气能见度的变化&#xff0c;为多个领域提供重要的数据支持。主要基于光在大气中的衰减规律。传感器系统中的发射器发出光线&#xff0c;照射到空…

shell编程--正则表达式

正则表达式 正则表达式都被置于两个正斜杠之间&#xff1b;如/l[oO]ve/ 示例 匹配数字的脚本&#xff0c;用户输入创建账号的数量 语法&#xff1a; [[ ^[0-9]$ ]] 表示必须输入数字 #!/bin/bashwhile : do read -p "输入数字&#xff1a;" numif [[ $num ~ ^[…

产品需求过程管理重要性

产品需求过程管理重要性 背景 以下都是真实事项经历回顾&#xff0c;在产品开发过程中&#xff0c;产品经理与研发团队之间的沟通至关重要。然而&#xff0c;沟通不畅或信息缺失常常导致需求无法准确传达&#xff0c;最终影响产品的成功。以下是一些常见的问题&#xff1a; 1.需…

Jmeter执行多机联合负载

1、注意事项&#xff0c;负载机必须要安装jre&#xff0c;控制机则必须安装jdk。要配置同网段ip&#xff0c;双向关闭防火墙。 每个负载机要平均承担线程数。 具体执行事项查看上面截图所示&#xff0c;控制机和负载机配置。 2、先给负载机设置ip地址&#xff0c;保持与控制…

C++项目详细分析_WebServer

前言 项目地址 项目介绍 源码详细分析 项目路径如下&#xff1a; 1.webserver.cpp 头文件和构造函数 #include "webserver.h"WebServer::WebServer() {// http_conn类对象users new http_conn[MAX_FD];// root文件夹路径char server_path[200];getcwd(server…

prometheus基于文件的服务发现

之间讲到&#xff0c;prometheus监控的对象就来自于他的配置文件里面的targets&#xff0c;如果要新增被监控对象&#xff0c;就继续往targets里面加。 但这个缺点是&#xff0c;每次修改完后都得重启prometheus。有没有什么办法&#xff0c;能在不重启的情况下增加target呢&a…

【Qt】 QComboBox | QSpinBox

文章目录 QComboBox —— 下拉框QComboBox 属性核心方法核心信号QComboBox 使用 QSpinBox —— 微调框QSpinBox 属性核心信号QSpinBox 使用 QComboBox —— 下拉框 QComboBox 属性 QComboBox —— 表示下拉框 currentText ——当前选中的文本 currentindex ——当前选中的条…

【硬件知识】从零开始认识GPU

【硬件知识】从零开始认识GPU 一、GPU的发展史简介二、GPU主要构成三、GPU与AI的关系 一、GPU的发展史简介 GPU&#xff08;图形处理器&#xff09;的发展史是一段充满创新与变革的历程&#xff0c;它不仅改变了计算机图形显示的方式&#xff0c;还推动了高性能计算、人工智能…

盘点大模型中转 API 平台,并比较费用

1. 大模型中转 API 平台集合 1.1 DevAGI DevAGI开放平台 Open AI 价格 1.2 Deepbricks 官网价格 1.3 AiHubMix AiHubMix 官网 使用教程 价格&#xff1a; 1.4 WildCard 开卡订阅 WildCard官网 价格 有3.5% 的充值手续费&#xff0c;API 价格与 Open AI 一样 2. 价…

机器学习:opencv--图像边缘检测

目录 前言 一、图像边缘检测 1.边缘检测 2.边缘检测的方法 二、Sobel算子 1.Sobel算子 2.计算 3.代码实现 4.代码步骤解析 1.导入图片 2.处理x轴和y轴的边缘并相加 三、Scharr算子 1.Scharr算子 2.计算 3.代码实现 四、Laplacian算子 1.Lapla…

PHP 项目流水线部署与错误问题解决

在现代软件开发中&#xff0c;持续集成&#xff08;CI&#xff09;和持续部署&#xff08;CD&#xff09;已成为确保代码质量和加快发布速度的关键实践。本文将介绍如何构建一个 PHP 项目的流水线部署&#xff0c;涵盖从代码提交到生产环境的自动化流程。 #### 1. 什么是流水线…

高效能低延迟:EasyCVR平台WebRTC支持H.265在远程监控中的优势

TSINGSEE青犀视频EasyCVR视频汇聚平台在WebRTC方面确实支持H.265编码&#xff0c;尽管标准的WebRTC API在大多数浏览器中默认并不支持H.265&#xff08;也称为HEVC&#xff0c;高效视频编码&#xff09;编码。EasyCVR平台通过一系列创新的技术手段&#xff0c;实现了在WebRTC协…

深入Redis:细谈持久化

Redis的数据是保存在内存中的&#xff0c;内存里面的数据是不持久的&#xff0c;要想做到持久化&#xff0c;必须要把在内存中的数据储存到硬盘上。 Redis速度非常快&#xff0c;数据只有在内存中才有这样的速度&#xff0c;但是为了持久&#xff0c;数据还是要想办法保存到硬…

WordPress 资源展示型下载类主题 CeoMax-Pro_v7.6 开心版

WordPress 资源展示型下载类主题 CeoMax-Pro_v7.6 开心版&#xff1b; CeoMax-Pro是一款极致美观强大的WordPress付费资源下载主题&#xff0c;它能满足您所有付费资源下载的业务需求&#xff01; 你的想法与业务不能被主题所限制&#xff01;CeoMax-Pro强大的功能&#xff0…