当前位置: 首页 > news >正文

set和map结构的使用

个人主页:敲上瘾-CSDN博客

个人专栏:游戏、数据结构、c语言基础、c++学习、算法

目录

一、序列式容器和关联式容器

二、set和multiset

1.insert

2.erase

3.find

4.count

三、map和mapmulti

1.pair

2.insert

3.find

4.operator[ ]

5.erase

6.lower_bound和upper_bound

四、习题

1.环形链表||

1.算法原理

2.代码编写

2.随机链表的复制

​编辑

1.算法原理

2.代码编写


一、序列式容器和关联式容器

        在正式讲解set和map之前需要先了解这个概念——序列式容器和关联式容器。比如string、vector、list、deque等这些储存结构都是序列式容器。序列式容器的特点是它们的逻辑结构都是线性的,而且数据之间都没有关联性,对一个数据的增删查并不对其他数据造成影响,也不会对这个结构造成影响。

        而关联式容器就恰好相反,它的逻辑结构是非线性的,而且数据之间的关联性非常强,对其中一个数据进行改变会对整个数据结构造成影响,比如set,setmulti,map,mapmulti,undered_set,undered_map。

        这一章的主角set和map它们是一种树形结构,它们的底层是红黑树,即⼀颗平衡⼆叉搜索树
。不过这一章主要是来讲它们的使用,对底层的结构并不做探讨。

二、set和multiset

        首先区分一下set和multiset:set中一个值只能出现一次(即同一个key只能在set里面插入一个)。multiset内允许储存多个相同的值。

set的学习网址:set - C++ Reference (cplusplus.com)

1.insert

        insert接口主要作用是来插入元素的,它支持直接插入某一个元素,也支持插入某个迭代器区间。

如下:

	set<int> st;st.insert(999);vector<int> arr = { 1,5,3,2 };st.insert(arr.begin(), arr.end());

2.erase

        erase支持删除一个值,删除一个迭代器区间或一个迭代器。

如下:

st.erase(7);//删除某个值
st.erase(st.begin());//删除最小值
st.erase(st.begin(), st.end());//删除整个区间

注意:对于set迭代器的遍历是中序遍历,所以迭代器遍历结果是有序的。 

3.find

        find的使用比较简单,传入一个值然后会返回一个该值的迭代器,不存在则返回空,就不再多讲。

4.count

        count接口是用来返回set / multiset / map / multimap中某一个数据出现的个数,也可用来查找某个数据是否存在。

三、map和mapmulti

map的学习网址:map - C++ Reference (cplusplus.com)

        map和set的区别:set一块区域只储存一个关键字(记为key),而map储存的是一个key和value,key和value是一个映射关系,通过key可以找到对应的vaule。而它们的函数接口的用法都一样就不分开讲。

        map和multimap:map中一个键值对(key和value)只能出现一次(即同一个键值对只能在map里面插入一个)。multiset内允许储存多个相同的键值对。

1.pair

 pair学习网址:pair - C++ Reference (cplusplus.com)

    pair是一种模板类型,用于存储一对值,其中这两个值可以是不同类型。它位于头文件 utility 中。使用 pair 可以非常方便地存储和操作一对相关联的数据,比如一个键(key)和一个值(value),这在许多算法和数据结构中都非常有用,如哈希表、映射(map)等。

    pair 有两个成员变量,通常称为 first 和 second,分别用来存储这一对值。这两个成员的类型可以不同,但它们都是在 pair 被声明时指定的。

pair有映射和集合的作用,标准库中的 mapmultimapunordered_map 和 unordered_multimap 等容器内部都使用 pair 来存储键值对。

2.insert

        因为map在做插入和各种处理时,key和value的关联性很强,而且如果kay和value分散开放的话会使map的迭代器无法获取到key和value的值。所以使用了pair结构,pair的作用相当于把key和value绑定在一起。

所以insert的插入方法有以下几种:

2.1.先创建一个pair变量并储入键值对,然后再利用插入map中。

map<string, string> dict;
pair<string, string> kv1("left", "左");
dict.insert(kv1);

 2.2.创建匿名pair对象插入map中

map<string, string> dict;
dict.insert(pair<string, string>("left", "左"));

2.3.使用make_pair 

map<string, string> dict;
dict.insert(make_pair("left", "左"));

make_pair这个接口的底层同样用了pair,不过它可以自动识别数据类型,减少了模板类型的填写。

2.4.c++11之后支持pair的隐式构造。

map<string, string> dict;
dict.insert({ "left", "左" });

        对于以上的几种插入,insert都会返回pair<interator, bool>,即如果插入失败,返回的就是nullptr和false,如果插入成功或该数据已经存在则返回该位置的迭代器和true。所以insert同时具备插入和查找功能。

注意在做迭代器遍历的时候,pair的first成员是key,second成员是value。

3.find

        map的查找呢是传入一个key值,然后对其查找,然后返回对应的迭代器,注意:map不支持对key进行修改,但支持对value进行修改。

4.operator[ ]

        这个运算符重载的功能比较全面,它既有查找的功能,也有修改和插入的功能。它需要传入一个key,注意只能是key,因为是要用key去查找。

如果找到则返回这个key对应的value的引用

如果没找到插入这个key然后返回对应的value的引用。

所以我们可以完成下面的操作:

map<string, string> dict;
dict["right"];//right不存在完成插入操作
dict["left"]="左边";//left不存在进行插入并且修改
dict["left"] = "左边,剩余的";//left存在完成查找并且修改

5.erase

        传入一个key,按中序遍历找到key并且删除所有key关键字的键值对。其他性质与set类似。

6.lower_bound和upper_bound

lower_bound 的作用:

    lower_bound 函数用于在一个有序器中查找第一个大于等于给定值的元素。它返回一个迭代器,指向该元素。如果容器中不存在大于等于给定值的元素,则返回指向容器末尾的迭代器。

upper_bound 的作用:

    upper_bound 函数用于在一个有序容器中查找第一个大于给定值的元素。它同样返回一个迭代器,指向该元素。如果容器中不存在大于给定值的元素,则返回指向容器末尾的迭代器。

    lower_bound 和 upper_bound 搭配使用可以确定一个左闭右开的迭代器区间。这个区间由 lower_bound 返回的迭代器(包含)和 upper_bound 返回的迭代器(不包含)界定。

这两个函数对于set、map、vector等等使用方法都是相同的。

四、习题

1.环形链表||

1.算法原理

        这个题是链表学习中的一个经典的题目,给一个链表然后判断这个链表是否有环,如果有环返回入环口处的节点,如果没有则返回空。

        方法一:快慢指针。该题可以用一个快慢指针同时从链表头开始走,如果快指针走到空节点还未与慢指针相遇,则该链表无环。如果快指针与慢指针相遇,则有环并记录相遇点,找两个速度相同的指针一个从头开始走,一个从相遇点开始走,那么它们相遇时的点就为环的入口点。这个算法比较难以想到,而且一眼难以看出它的正确性需要有严谨的证明。我在以下文章中有详细讲解:链表经典面试题-CSDN博客

        方法二:使用一个指针从链表的头走到尾,并且使用一个set容器,每走一步判断set中是否已存入该值,如果没有则存入,如果有那么这个链表一定有环并且该点就是环的入口点,直接返回该值即可。如果指针走到空依旧没有找到set中的重复值则这个链表不带环,返回空。该方法灵活运用了数据结构,而且很容易理解,相比上一个解法直接就是降维打击。

2.代码编写

class Solution {
public:ListNode *detectCycle(ListNode *head) {set<ListNode*> pt;ListNode* cur=head;while(cur){if(pt.count(cur)) return cur;else pt.insert(cur);cur=cur->next;}return nullptr;}
};

2.随机链表的复制

1.算法原理

        该题是对一个随机链表进行深拷贝,给一个链表要求原模原样拷贝一份,而这个题的难点并不在于拷贝节点本身,而是在于拷贝节点后random指向的节点是什么。尽管我们知道原链表的random指向什么但很难根据旧空间random的指向来判断新空间random的指向。不过因为旧空间与新空间有一个一一映射关系,所以我们可以使用一个map,key储存旧空间的值,value储存新空间的值。这个时候就非常好办只需旧空间的random找到指向的key就能找到新空间random应该指向的value。

2.代码编写

class Solution
{
public:Node* copyRandomList(Node* head){map<Node*,Node*> mp;Node* cur=head;Node* rhead=nullptr,*ret=nullptr,*perv=nullptr;while(cur){Node* ret=new Node(cur->val);if(rhead==nullptr) rhead=ret;else perv->next=ret;mp[cur]=perv=ret;cur=cur->next;}ret=rhead;cur=head;while(ret){ret->random=mp[cur->random];ret=ret->next;cur=cur->next;}return rhead;}
};

http://www.lryc.cn/news/450800.html

相关文章:

  • 2. qt_c++反射实例
  • 卷积神经网络(CNN)的计算量和参数怎么准确估计?
  • Ruby基础语法
  • 插入排序C++
  • 修改ID不能用关键字作为ID校验器-elementPlus
  • 一文详解WebRTC、RTSP、RTMP、SRT
  • 全国职业院校技能大赛(大数据赛项)-平台搭建Zookeeper笔记
  • 不同领域神经网络一般选择什么模型作为baseline(基准模型)
  • 华为-IPv6与IPv4网络互通的6to4自动隧道配置实验
  • 【spring中event】事件简单使用
  • leetcode每日一题day19(24.9.29)——买票需要的时间
  • 智源研究院推出全球首个中文大模型辩论平台FlagEval Debate
  • python实用脚本(二):删除xml标签下的指定类别
  • vue3 父子组件调用
  • 线性模型到神经网络
  • 【架构】前台、中台、后台
  • Stable Diffusion 蒙版:填充、原图、潜空间噪声(潜变量噪声)、潜空间数值零(潜变量数值零)
  • ffmpeg录制视频功能
  • 【LeetCode】每日一题 2024_10_1 最低票价(记忆化搜索/DP)
  • [C++] 小游戏 征伐 SLG DNF 0.0.1 版本 zty出品
  • 黑马头条day7-app端文章搜索
  • 嵌入式必懂微控制器选型:STM32、ESP32、AVR与PIC的比较分析
  • Python selenium库学习使用实操二
  • 基于Hive和Hadoop的电信流量分析系统
  • 访问docker容器中服务的接口,报错提示net::ERR_CONNECTION_REFUSED
  • 【mysql相关总结】
  • uniapp 微信小程序 微信支付
  • CSS 效果:实现动态展示双箭头
  • Linux 创建开发用的账户
  • 检查一个CentOS服务器的配置的常用命令