目录
[Part1. C++容器的分类](#Part1. C++容器的分类)
[Part2. set介绍及使用](#Part2. set介绍及使用)
[Part2.1. 基本构成](#Part2.1. 基本构成)
[Part2.2. 比较器相关小知识](#Part2.2. 比较器相关小知识)
[Part2.3. 插入函数与构造函数](#Part2.3. 插入函数与构造函数)
[Part2.4. 核心接口的使用](#Part2.4. 核心接口的使用)
[Part2.5. multiset 与 set 在函数上的区别](#Part2.5. multiset 与 set 在函数上的区别)
[Part2.6. set的使用](#Part2.6. set的使用)
[Part3. map介绍及使用](#Part3. map介绍及使用)
[Part3.1. 基本构成](#Part3.1. 基本构成)
[Part3.2. 插入函数与构造函数](#Part3.2. 插入函数与构造函数)
[Part3.3. 键重复规则](#Part3.3. 键重复规则)
[Part4. 结语](#Part4. 结语)
前言
map和set作为C++很重要的容器,了解他们是很必要的。接下来,跟随小编的视角来看看这两个容器的介绍和基本的使用吧。
let's go!!!!!!!!!
Part1. C++容器的分类
C++有着许许多多的容器,大致的根据其存储的数据之间的关系可以分为两类,即:
<1> 序列式容器
主要特征:数据之间没有关联,仅仅是有序存放。
代表:string、vector、list、array<2> 关联式容器
主要特征:数据与数据之间存在关联(例如二叉树中的父子关系)。
代表:map、set
Part2. set介绍及使用
Part2.1. 基本构成
<1> Set的模板参数为这三个元素:template <class T, class compare = less<T>, class Alloc>(存放元素的类型、比较器(仿函数)、空间配置器)
<2> 同时其增删查的时间复杂度:O(logN)(高度次)
<3> 迭代器类型:双向迭代器,支持++、--。
<4> 限制:不支持直接修改元素值,修改会破坏二叉搜索树的有序性。如果要修改,只能先删除旧值,再插入新值。
Part2.2. 比较器相关小知识
<1> 基本知识:默认比较器 less<T>:左 < 右,从小到大升序排列。如果传入 greater<int>,则变为从大到小降序。
<2> 但是通常比较器只有<比较函数,如何实现>逻辑?由于a > b 等价于 b < a,只需要把两个参数交换位置调用比较函数即可(a>b <=> less<>(b,a))。
Part2.3. 插入函数与构造函数
cppset<int> s; s.insert({1,2,4}); set<int> a={1,2,3}; set<int> b({2,3,2});//构造函数调用insert进行列表初始化
Part2.4. 核心接口的使用
<1> find(x) 找到元素则返回对应迭代器,找不到返回end() 。
<2> erase(x) 可以传入迭代器或者元素值。传入值时会删除所有匹配元素,返回成功删除的元素个数。
<3> count(x) 返回元素的个数,在set中结果只能是0或1,常用于判断元素是否存在。
<4> lower_bound(val) 返回第一个 ≥ val 元素的迭代器
<5> upper_bound(val) 返回第一个 > val 元素的迭代器
<6> lower_bound(val)和upper_bound(val)的应用:
cpp//删除区间 [30, 50] 内所有元素: set<int>::iterator left = st.lower_bound(30); auto right = st.upper_bound(50); st.erase(left, right); //为什么右端要用upper_bound?因为erase是左闭右开区间[left, right),使用upper_bound才能把等于50的元素一并删掉。
Part2.5. multiset 与 set 在函数上的区别
<1> 由于multiset中会有重复的元素。对于这种情况,find函数会返回在中序遍历中第一个出现的元素的迭代器。
<2> 具体实现的思路是:找到了元素就继续往它的左子树中去找,直到找到nullptr结束,返回这个过程之最后遇到的元素的迭代器。
Part2.6. set的使用
cppclass Solution { public: ListNode *detectCycle(ListNode *head) { set<ListNode*> aaa; while(head!=nullptr) { if(aaa.count(head)==0)//如果检测到set中有这个元素 就说明这是第一个重复的元素 也就是链表环的起点 用set关键在于把检测是否存在的时间复杂度降为O(logN) { aaa.insert(head); head=head->next; } else { break; } } return head; } };
题目链接:142. 环形链表 II - 力扣(LeetCode)
cppclass Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { set<int> s1; for(auto i:nums1) { s1.insert(i);//初始化S1 } set<int> s2; for(auto i:nums2) { s2.insert(i); } vector<int> ans; set<int>::iterator it1=s1.begin(); auto it2=s2.begin(); while(it1!=s1.end()&&it2!=s2.end()) { if(*it1==*it2) { ans.push_back(*it1); it1++; it2++; } else if(*it1<*it2)//由于set遍历为中序遍历 有序 就像合并两个有序数组一样 小的先走 { it1++; } else { it2++; } } return ans; } };
题目链接:349. 两个数组的交集 - 力扣(LeetCode)
交差补集在现实中的应用:云端数据与本机数据的同步。
Part3. map介绍及使用
Part3.1. 基本构成
<1> template <class Key, class Value, class Compare, class Alloc>(同set)
<2> 存储单元:pair<const Key, T>。其中他的两个成员,first:对应键key,const 不可修改。second:对应值value,允许修改。
cppmap<int, int>::iterator it = mp.begin(); cout << it->first << endl; // 获取key cout << it->second << endl; // 获取value
Part3.2. 插入函数与构造函数
cppmap<string, string> mp; <1> pair<string, string> k = {"aaa", "bbb"};//实例化对象插入 mp.insert(k); <2> mp.insert(make_pair("aaa", "bbb"));//临时对象插入 <3> mp.insert({"aaa", "bbb"});//C++11 构造函数另一种用法:map<string, string> mp = {{"name", "zhangsan"},{"age", "20"}};//与插入函数结合
Part3.3. 键重复规则
当插入key相同、value不同的数据时:insert不会覆盖原有旧数据,新键值对直接插入失败。可以通过it->second直接修改value。
Part4. 结语
上面我们介绍了set和map的介绍和基本使用,接下来小编还会有更多文章关于这两个的,也请敬请期待~
最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~


