【C++指南】你真的了解map和set吗?【上】_c++set迭代器
🌟 各位看官好,我是egoist2023!
🌍 种一棵树最好是十年前,其次是现在!
🚀 今天来学习map和set的相关用法。
💬 注意:本文小编截取了set、map系列的常用接口,并做了相对应修改,减小学习成本。
👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦!
目录
序列式、关联式容器
set系列的使用
构造及迭代器
增删查
multiset
两个数组的交集
环形链表II
序列式、关联式容器
序列式容器:前文所讲的STL中的string、vector、list、deque、array、forward_list等容器,我们都称为序列式容器,因为它们的逻辑结构是线性序列的,两个位置存储的值之间⼀般没有紧密的关联关系,⽐如交换⼀下,他依旧是序列式容器。
关联式容器:它是用来存储数据的,其逻辑结构通常是非线性结构,并且两个位置有紧密的联系(如二叉搜索树),只要交换某两个值的位置,它的存储结构就被破坏了。而关联式容器就包括本章节所接触到的map/set系列以及之后的unordered_map/unordered_set系列。(map和set的底层是依赖红黑树,并且set即是我们前文所讲的key搜索场景,map相对应便是Key/Value场景。
set系列的使用
需要注意的是,本章节小编只截取了set中常用的接口(参数类型做了相应删减),降低学习成本。如需了解更多的接口访问此网站。
构造及迭代器
template<class T,class Compare = less,class Alloc = allocator>
set (InputIterator first, InputIterator last)
set (const set& x)
set (initializer_list il)
iterator begin()
iterator end()
reverse_iterator rbegin()
reverse_iterator rend()
int main(){//排序 和 去重set s;s.insert(1);s.insert(2);s.insert(3);s.insert(2);s.insert(4);set::iterator it = s.begin(); //正向迭代器//auto it = s.begin();while (it != s.end()) //正向迭代器{cout << *it << \" \";it++;}return 0;}
有迭代器,那么就支持范围for
for (auto& e : s){cout << e << \" \";}
插入一段initializer_list列表值
set s = { 1,3,1,2,5 };
增删查
由于set是序列式容器,并不支持改的操作,因为一旦改动某个结点的值,那么它的存储结构就被破坏了。
pair insert (const T& val)
void insert (initializer_list il)
void insert (InputIterator first, InputIterator last)
iterator erase (const_iterator position)
size_t erase (const T& val)
iterator erase(const_iterator first, const_iterator last)
iterator find (const T& val)
为什么插入接口的返回值是pair,不应该是bool吗?且pair又是什么呢?
- 统一接口:在map系列的容器当中,Key/Value并不像二叉搜索树那样直接封装在树的结构体中,而是封装在pair中,这是因为在查找等情况C++无法做到返回多个值,但通过封装的方式达到返回多个值的目的。
- 所有关联容器(
map
、set
、unordered_map
等)的插入操作遵循相同的返回值约定,降低学习成本。- pair的封装,表示键值对。
template struct pair { T1 first; // 第一个值 T2 second; // 第二个值};
为什么erase的返回值是size_t,不应该是bool吗?(插入失败返回0)
- 同样,这里的目的是为了统一接口,因为在multiset中是支持插入相同的数(即支持冗余),在删除后可能返回多个数的情况,而set中只能存在0和1的情况,做到了两个类的ease使用同一个函数。
在C++11版本后支持initializer_list列表初始化、插入等,将需要插入的值用{}的方式(多参数隐式类型转换)。
multiset
multiset (initializer_list il)
size_t erase (const T& val)
iterator find (const T& val)
size_t count (const T& val) const
由于multiset是支持冗余的版本,导致了一些接口是和set不相同的,部分如上所示。
// 相⽐set不同的是,multiset是排序,但是不去重multiset s = { 4,2,7,2,4,8,4,5,4,9 };// 相⽐set不同的是,count会返回x的实际个数cout << s.count(x) << endl;// 相⽐set不同的是,erase给值时会删除所有的xs.erase(x);
两个数组的交集
需要对两个数组采交集,那么可以先使用set容器对数据去重,然后采用同步算法的思想返回交集。
vector ret; set s1(nums1.begin(),nums1.end()); set s2(nums2.begin(),nums2.end()); auto cur1=s1.begin(),cur2=s2.begin(); while(cur1!=s1.end()&&cur2!=s2.end()) { if(*cur1*cur2) cur2++; else { ret.push_back(*cur1); cur1++; cur2++; } } return ret;
环形链表II
在还没学习set系列时,我们采用的是快慢指针的思想解决环形链表的问题。
在这里采用的是set实例化出ListNode*结点指针,只有当两个指针的地址相同时会出现环形的问题。
set s; ListNode* cur=head; while(cur) { if(s.count(cur)==0) { s.insert(cur); } else return cur; cur=cur->next; } return nullptr;