[STL]set存储pair并自定义排序
本文介绍了C++中set<> 容器的基本使用方法,并通过一个具体用例介绍了使用set<>容器存储pair<>对象,以及自定义set<>容器排序规则的用法。还详细介绍了使用set容器存储pair对象时需要注意的事项。
一、set定义
c++官方对set的定义如下:
Set:Sets are containers that store unique elements following a specific order.
Set:set是一类用来存储满足一定排序的独一元素的容器。
类模板如下:
template < class T, // set::key_type/value_type
class Compare = less<T>, // set::key_compare/value_compare
class Alloc = allocator<T> // set::allocator_type
> class set;
可以看到set模板类有三个参数:
- T:set容器中的元素类型。
- Compare:比较类,定义容器中元素排序,缺省为less< T >。
- Alloc:内存分配器。一般使用缺省值。
二、set< int >实例
set<int, less<int> > set_less;
set<int, greater<int> > set_greater;
for(int i=0; i<10; i++){
set_less.insert(i%3);
set_greater.insert(i%3);
}
// 遍历
for(set<int, less<int> >::iterator iter=set_less.begin(); iter!=set_less.end(); iter++){
cout<<*iter<<" ";
}
cout<<endl;
for(set<int, greater<int> >::iterator iter=set_greater.begin(); iter!=set_greater.end(); iter++){
cout<<*iter<<" ";
}
输出为:
0 1 2
2 1 0
三、set< pair< int , int>>实例
1.默认pair<int, int>排序
set<pair<int, int> > set_pair;
for(int i=0; i<10; i++){
set_pair.insert(pair<int, int>(i, i%3));
}
for(set<pair<int, int> >::iterator iter=set_pair.begin(); iter!=set_pair.end(); iter++){
cout<<"("<<iter->first<<","<<iter->second<<") ";
}
cout<<endl;
输出为:
(0,0) (1,1) (2,2) (3,0) (4,1) (5,2) (6,0) (7,1) (8,2) (9,0)
2.使用less、greater排序
使用less:
set<pair<int, int>, less<pair<int, int>> > set_pair_less;
for(int i=0; i<10; i++){
set_pair_less.insert(pair<int, int>(i, i%3));
}
for(set<pair<int, int>, less<pair<int, int>> >::iterator iter=set_pair_less.begin(); iter!=set_pair_less.end(); iter++){
cout<<"("<<iter->first<<","<<iter->second<<") ";
}
cout<<endl;
输出为:
(0,0) (1,1) (2,2) (3,0) (4,1) (5,2) (6,0) (7,1) (8,2) (9,0)
使用greater:
set<pair<int, int>, greater<pair<int, int>> > set_pair_greater;
for(int i=0; i<10; i++){
set_pair_greater.insert(pair<int, int>(i, i%3));
}
for(set<pair<int, int>, greater<pair<int, int>> >::iterator iter=set_pair_greater.begin(); iter!=set_pair_greater.end(); iter++){
cout<<"("<<iter->first<<","<<iter->second<<") ";
}
cout<<endl;
输出为:
(9,0) (8,2) (7,1) (6,0) (5,2) (4,1) (3,0) (2,2) (1,1) (0,0)
使用less<>、greater<>模板对pair< int , int >排序时,先比较pair的第一个元素,如果第一个元素相等再比较第二个元素。
3.自定义排序
例如,我们使用pair<char, int>记录字符串中字符的顺序时(实际上使用map<char, int>容器记录会更方便),希望set中的字符按照频率升序排列(频率相同时,顺序不做要求),几种自定义set排序的代码如下:
#include <set>
#include <iostream>
#include <vector>
using namespace std;
class Cmp {
public:
// 重载 () 操作符
// 参数必须加上const限定符
bool operator()(const pair<char, int>& a, const pair<char, int>& b) const {
return a.second == b.second ? (a.first < b.first) : (a.second < b.second);
}
};
int main() {
string str = "icaneatglass";
vector<int> vec(26, 0);
for (int i = 0; i < str.length(); i++) {
vec[str[i] - 'a'] ++;
}
// 使用仿函数自定义set排序
set<pair<char, int>, Cmp> set_pair_functor;
// 使用lambda表达式自定义排序
auto cmp = [](const pair<char, int>& a, const pair<char, int>& b) {
return a.second == b.second ? (a.first < b.first) : (a.second < b.second);
};
set<pair<char, int>, decltype(cmp)> set_pair_lambda(cmp);
// 插入数据
for (int i = 0; i < 26; i++) {
if (vec[i] != 0) {
set_pair_functor.insert(pair<char, int>((char)('a' + i), vec[i]));
set_pair_lambda.insert(pair<char, int>((char)('a' + i), vec[i]));
}
}
// 输出
for (auto it : set_pair_functor) {
cout << "(" << it.first << "," << it.second << ")";
}
cout << endl;
for (auto it : set_pair_lambda) {
cout << "(" << it.first << "," << it.second << ")";
}
cout << endl;
return 0;
}
输出为:
(c,1)(e,1)(g,1)(i,1)(l,1)(n,1)(t,1)(s,2)(a,3)
(c,1)(e,1)(g,1)(i,1)(l,1)(n,1)(t,1)(s,2)(a,3)
需要注意的是,尽管排序时我们只需要考虑pair< char, int>中的第二个参数,频率(int);不需要考虑第一个参数,字符(char)。但是在仿函数Cmp的()运算符重载中,也必须进行字符比较。
如果写成如下(下面的代码是错误的):
class Cmp{
public:
bool operator()(const pair<char, int> &a, const pair<char, int> &b) const{
return a.second<b.second;
}
};
// 其他部分代码都相同
...
最终的输出为:
(c,1) (s,2) (a,3)
这是因为:前面已经提到set中只会 store unique elements,即对于"相等"的元素set中只存储一个。而set中用Cmp类来判断两个元素是否equal。假如两个元素a和b,Cmp(a,b)返回false,Cmp(b,a)也返回false,那么就认为a和b相等。假如a和b的second(在本例中代表字符的频率)相等,那么set会只存储最后插入的元素,这就导致最终set中只会存储second(字符的频率)不同的元素。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)