🦄个人主页:修修修也
🎏所属专栏:C++
⚙️操作环境:Visual Studio 2022
目录
📌关联式容器set(集合)简介
📌set(集合)的使用
🎏set(集合)的模板参数列表
🎏set(集合)的构造函数
🎏set(集合)的迭代器
🎏set(集合)的容量
🎏set(集合)的修改操作
📌关联式容器multiset简介
📌关联式容器multiset使用
结语
在之前对STL的学习中,我们已经接触过STL中的部分容器,比如:vector、list、deque、forward_list(C++11)等,根据"数据在容器中的排列"特性,这些容器统称为序列式(sequence)容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。
还有一种容器是关联式(associative)容器, 关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。
下图列出了STL中的各种容器,以及其基层与衍生层的关系:
📌关联式容器set(集合)简介
我们先来看一下cplusplus.com - The C++ Resources Network网站对set的文档介绍:
总结一下:
- set是按照一定次序存储元素的容器。
- 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
- 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
- set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
- set在底层是用二叉搜索树(红黑树)实现的。
注意:
- 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
- set中插入元素时,只需要插入value即可,不需要构造键值对。
- set中的元素不可以重复(因此可以使用set进行去重)。
- 使用set的迭代器遍历set中的元素,可以得到有序序列。
- set中的元素默认按照小于来比较。
- set中查找某个元素,时间复杂度为:。
- set中的元素不允许修改(因为修改key可能会导致二叉搜索树结构被破坏)。
- set中的底层使用二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))来实现。
📌set(集合)的使用
🎏set(集合)的模板参数列表
set的模板参数及含义如下:
🎏set(集合)的构造函数
set的构造函数及其功能如下:
使用示例如下:
#include<iostream> #include<vector> #include<set> using namespace std;int main() {//构造一个没有元素的空容器set<int> s1;for (auto e : s1){cout << e << " ";}cout << endl;vector<int> v;v.push_back(2);v.push_back(5);v.push_back(1);v.push_back(4);v.push_back(3);//迭代器区间构造set<int> s2(v.begin(), v.end());for (auto e : s2){cout << e << " ";}cout << endl;//拷贝构造set<int> s3(s2);for (auto e : s3){cout << e << " ";}cout << endl;return 0; }
运行效果如下:
🎏set(集合)的迭代器
set的迭代器相关函数及其功能如下:
使用示例如下:
int main() {vector<int> v;v.push_back(2);v.push_back(5);v.push_back(1);v.push_back(4);v.push_back(3);//迭代器区间构造set<int> s(v.begin(), v.end());//正向迭代器set<int>::iterator it_b = s.begin(); //访问正向迭代器开始cout << *it_b << endl;set<int>::iterator it_e = s.end(); //访问正向迭代器结束--it_e; cout << *it_e << endl;++it_e;while (it_b != it_e){cout << *it_b << " "; //使用正向迭代器遍历set++it_b;}cout << endl;//反向迭代器set<int>::reverse_iterator rit_b = s.rbegin(); //访问反向迭代器开始cout << *rit_b << endl;set<int>::reverse_iterator rit_e = s.rend(); //访问反向迭代器结束--rit_e;cout << *rit_e << endl;++rit_e;while (rit_b != rit_e){cout << *rit_b << " "; //使用反向迭代器遍历set++rit_b;}cout << endl;return 0; }
运行结果如下:
🎏set(集合)的容量
set的容量相关函数及其功能如下:
使用示例如下:
int main() {//构造一个没有元素的空容器set<int> s1;cout << s1.empty() << endl;cout << s1.size() << endl;cout << s1.max_size() << endl;vector<int> v;v.push_back(2);v.push_back(5);v.push_back(1);v.push_back(4);v.push_back(3);//迭代器区间构造set<int> s2(v.begin(), v.end());cout << s2.empty() << endl;cout << s2.size() << endl;cout << s2.max_size() << endl;return 0; }
运行结果如下:
🎏set(集合)的修改操作
set的修改相关函数及其功能如下:
函数声明 功能介绍 pair<iterator, bool> insert(const value_type&x) 在set中插入元素x,实际插入的是<x, x>构成的
键值对,如果插入成功,返回<该元素在set中的
位置,true>,如果插入失败,说明x在set中已经
存在,返回<x在set中的位置,false>void erase ( iterator position ) 删除set中position位置上的元素
size_type erase ( const key_type& x ) 删除set中值为x的元素,返回删除的元素的个数 void erase ( iterator first, iterator last ) 删除set中[first, last)区间中的元素 void swap ( set<Key,Compare,Allocator>& st ) 交换两个set中的元素 void clear ( ) 将set中的元素清空 iterator find ( const key_type& x ) const 返回set中值为x的元素的位置 size_type count ( const key_type& x ) const 返回set中值为x的元素的个数 insert,erase,clear,find函数使用示例如下:
int main() {//构造一个没有元素的空容器set<int> s1;//插入元素s1.insert(3);s1.insert(1);s1.insert(7);s1.insert(4);s1.insert(0);s1.insert(8);s1.insert(2);s1.insert(6);s1.insert(9);s1.insert(5);for (auto k : s1){cout << k << " ";}cout << endl;set<int>::iterator pos = s1.find(1);//迭代器删除元素s1.erase(pos);for (auto k : s1){cout << k << " ";}cout << endl;//key值删除元素s1.erase(3);for (auto k : s1){cout << k << " ";}cout << endl;//迭代区间删除元素s1.erase(s1.begin(), s1.find(5));for (auto k : s1){cout << k << " ";}cout << endl;//清空set中的元素s1.clear();for (auto k : s1){cout << k << " ";}cout << endl;return 0; }
运行结果如下:
swap函数使用示例如下:
int main() {//构造两个没有元素的空容器set<int> s1;set<int> s2;//s1中插入元素s1.insert(3);s1.insert(1);s1.insert(4);s1.insert(0);s1.insert(2);cout << "s1 : ";for (auto k : s1){cout << k << " ";}cout << endl;cout << "s2 : ";for (auto k : s2){cout << k << " ";}cout << endl;//交换s1和s2的值s1.swap(s2);cout << "s1 : ";for (auto k : s1){cout << k << " ";}cout << endl;cout << "s2 : ";for (auto k : s2){cout << k << " ";}cout << endl;return 0; }
运行结果如下:
count()函数的定义如下图:
count函数使用示例如下:
int main() {//构造一个没有元素的空容器set<int> s1;//s1中插入元素s1.insert(3);s1.insert(1);s1.insert(4);s1.insert(0);s1.insert(2);cout << "s1 : ";for (auto k : s1){cout << k << " ";}cout << endl;cout << s1.count(2) << endl;cout << s1.count(4) << endl;cout << s1.count(6) << endl;cout << s1.count(8) << endl;return 0; }
运行结果如下:
📌关联式容器multiset简介
我们先来看一下cplusplus.com - The C++ Resources Network网站对set的文档介绍:
总结一下:
- multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。
- 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。
- 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。
- multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列。
- multiset底层结构为二叉搜索树(红黑树)
注意:
- multiset中再底层中存储的是<value, value>的键值对
- mtltiset的插入接口中只需要插入即可
- 与set的区别是,multiset中的元素可以重复,set是中value是唯一的
- 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
- multiset中的元素不能修改
- 在multiset中找某个元素,时间复杂度为$O(log_2 N)$
- multiset的作用:可以对元素进行排序
📌关联式容器multiset使用
multiset的接口是和set一模一样的,区别在于具体的使用上:
首先,multiset支持插入重复的键值key, 这就意味着multiset没有set的去重作用 :
int main() {//构造一个没有元素的空容器setset<int> s;s.insert(3);s.insert(1);s.insert(5);s.insert(5); //插入多个重复键值keys.insert(5);s.insert(4);s.insert(5);s.insert(2);for (auto e : s){cout << e << " ";}cout << endl;//构造一个没有元素的空容器multisetmultiset<int> ms;ms.insert(3);ms.insert(1);ms.insert(5);ms.insert(5); //插入多个重复键值keyms.insert(5);ms.insert(4);ms.insert(5);ms.insert(2);for (auto e : ms){cout << e << " ";}cout << endl;return 0; }
运行结果如下:
同时,对于set模板里几乎没有什么意义的几个函数接口在multiset这里就可以得到很好的应用了,如:count,equal_range等函数:
如下代码,我们利用count函数计算multiset中5出现的次数,并利用equal_range函数将其全部删除:
int main() {//构造一个没有元素的空容器multisetmultiset<int> ms;ms.insert(3);ms.insert(1);ms.insert(5);ms.insert(5); //插入多个重复键值keyms.insert(5);ms.insert(4);ms.insert(5);ms.insert(2);for (auto e : ms){cout << e << " ";}cout << endl;//计算5出现的次数cout << "5出现的次数: " << ms.count(5) << endl;//删掉所有的5pair<multiset<int>::iterator, multiset<int>::iterator> ret = ms.equal_range(5); //这里ret的类型直接用auto也行multiset<int>::iterator left = ret.first;multiset<int>::iterator right = ret.second;ms.erase(left, right);for (auto e : ms){cout << e << " ";}cout << endl;return 0; }
运行结果如下:
结语
希望这篇关于 STL标准模板库容器set 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.
学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!
相关文章推荐
【C++】模拟实现二叉搜索(排序)树
【数据结构】C语言实现链式二叉树(附完整运行代码)
【数据结构】什么是二叉搜索(排序)树?
【C++】模拟实现priority_queue(优先级队列)
【C++】模拟实现queue
【C++】模拟实现stack
【C++】模拟实现list
【C++】模拟实现vector
【C++】标准库类型vector
【C++】模拟实现string类
【C++】标准库类型string
【C++】构建第一个C++类:Date类
【C++】类的六大默认成员函数及其特性(万字详解)
【C++】什么是类与对象?