C++ set和map的简单使用
C++中的STL模板库的功能可谓相当强大。今天我们来简单说一下set和map的使用方法。
1.pair
我们先来说一下pair。pair定义在头文件<utility>中,其本身相当于一个已经重定义过的,有两个元素的结构体。它始终以前一个元素(first)为第一关键字,后一个元素(second)为第二关键字。在set或是其他STL容器中使用的时候自动进行按此排序。
pair的定义很简单,定义如下:
pair <int,int> q;
当然里面的数据类型可以改变,后面的变量名也可以任意改变。
或者你可以使用make_pair来新建一个pair,比如:
make_pair(s,t);
在新建pair的时候可以直接赋值,有两种方法,第一种如下:
pair <int,string> p1(0,"Hello");
就是在定义的pair的名称后面打上括号,里面直接把值传进去。
第二种如下:
pair <int,string> p2 = make_pair(1,"World");
这样的话就是使用一次makepair来对pair赋初值了。
看起来很简单。这样我们就可以在STL中使用pair这种数据结构类型,以进行各种复杂的操作……而在向里面压入pair元素的时候,只要加一个make_pair就可以了。
2.map
map本身是键值(key)和映射值(value)的一个映射。其中key和value可以选择任意数据类型。
(1)创建一个map
这里使用最简单的一种方法,就是直接定义一个map,在里面写上key和value的类型,再定义map的名字。
map <int,int> mp;
(2)向map中添加元素
第一种是直接使用map的下标进行添加,就像使用数组一样。比如:
for(int i = 1;i <= n;i++) mp[i] = i * 100;
第二种是使用insert函数,将一个pair元素进行插入。比如:
for(int i = 1;i <= 10;i++) mp.insert(make_pair(i,i*100));
以及还有许多神奇的添加方式,在这里不一一讲述了……
(3)在map中查找元素
如果要直接查找元素在map中出现过多少次,那么可以使用count函数,比如:
map <int,int> mp; rep(i,0,19) mp.insert(make_pair(i,i*100)); if(mp.count(1)) printf("Yes\n");
注意这里的count是直接查找键值(key)。
而且因为map中会自动对相同键值去重……所以count相当于只会告诉你这个元素是否有出现过。如果想使用count计算元素出现次数可以使用multimap。
map还有find()函数,可以返回指向所查找元素的迭代器,如果没有此元素就返回指向map尾部的迭代器。
比如:
map <int,int> :: iterator itf; itf = mp.find(19); if(itf != mp.end()) itf->second = 20;
注意因为itf是一个迭代器(实际上是指针),所以我们使用了->,如果不愿意使用的话,也可以写成:
(*itf).second
最暴力的方式就是直接在map中用迭代器遍历,比如这样:
map <int,int> :: iterator it; for(it = mp.begin();it != mp.end();it++) printf("%d->%d\n",it->first,it->second);
因为在map中元素的地址是相连的,所以直接it++即可。如果不愿意用->就使用上面的写法。
还有非常强劲的查找方式,那就是直接使用lowerbound和upperbound。这里要提一下map里面的排序,他是自动按key值从小到大排序,也就是说不可以对map使用sort。
lowerbound和upperbound与平时在数组上的用法都是一样的,一般来说支持key值查找(value作为第二关键字可不可行我还不知道……)一般来讲,我们映射都是一一映射,所以key值应该都是唯一的,直接在key值上查找就可以了。
特别的,如果lower/upperbound找不到元素的话,返回指向容器末尾的迭代器。
(返回的类型如果你开了代码补全可以看到……不过很影响码速)
(4)map中删除元素
删除元素一般来说有三种操作。第一种是直接使用erase函数往里面传实际值,比如:
mp.erase(0);
第二种就是向里面传一个迭代器,比如:
mp.erase(mp.begin());//显然begin函数返回的是一个迭代器!!
第三种就是传两个迭代器,注意这样删除的是一个左闭右开的区间,比如:
map <int,int> mp; rep(i,0,19) mp.insert(make_pair(i,i)); map <int,int> :: iterator itf; itf = mp.upper_bound(15); mp.erase(mp.begin(),itf);
这样删完之后,你会发现元素还剩15~19,(15没有被删去),用upperbound的话就是16~19了。
这些操作已经基本够用了……还有一个很厉害的swap。这里的swap函数直接交换的是两个map容器,而不是元素。
(下面代码是偷来的)
#include <map> #include <iostream> using namespace std; int main( ) { map <int, int> m1, m2, m3; map <int, int>::iterator m1_Iter; m1.insert ( pair <int, int> ( 1, 10 ) ); m1.insert ( pair <int, int> ( 2, 20 ) ); m1.insert ( pair <int, int> ( 3, 30 ) ); m2.insert ( pair <int, int> ( 10, 100 ) ); m2.insert ( pair <int, int> ( 20, 200 ) ); m3.insert ( pair <int, int> ( 30, 300 ) ); cout << "The original map m1 is:"; for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ ) cout << " " << m1_Iter->second; cout << "." << endl; // This is the member function version of swap //m2 is said to be the argument map; m1 the target map m1.swap( m2 ); cout << "After swapping with m2, map m1 is:"; for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ ) cout << " " << m1_Iter -> second; cout << "." << endl; cout << "After swapping with m2, map m2 is:"; for ( m1_Iter = m2.begin( ); m1_Iter != m2.end( ); m1_Iter++ ) cout << " " << m1_Iter -> second; cout << "." << endl; // This is the specialized template version of swap swap( m1, m3 ); cout << "After swapping with m3, map m1 is:"; for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ ) cout << " " << m1_Iter -> second; cout << "." << endl; system("pause"); }
就是这样啦!
3.set
set即集合,内部是使用红黑树实现的(这么强劲的数据结构蒟蒻学不会QAQ)。不过set的操作还是非常值得学一学的。
(1)创建一个set。
set <int> q;
这是最简单的写法,里面的变量类型是任意的,比如什么pair啦或者是自己定义的结构体。
注意set在你没有进行重载运算符之前,默认是一个小根堆,而且会自动去重。
(2)向set里面插入元素
插入元素好像有好多好多奇妙的方法……不过我还是说最简单的吧,就是直接使用insert函数(set可不再支持用下标插入函数了)比如:
q.insert(3);//这是int版本的 q.insert((node){a,b,c})//如果你自定义一个结构体,就可以这么传(和平时往队列里面压一样)
(3)在set中查找元素
这里面好多函数在map中都介绍过了,而且在set中的用法和在map中基本一样,比如count,find等等。
不过,我们可以对结构体进行运算符重载,之后就可以愉悦的使用lowerbound对你想要的东西进行查找。
支持多关键字,多种排序方式,我们举个例子。
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #include<set> #include<vector> #include<utility> #include<map> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') struct node { int sum,val; bool operator < (const node &g)const { if(sum == g.sum) return val > g.val; return sum < g.sum; } } set <node> q; int main() { for(int i = 1;i <= n;i++) q.insert((node){a,b,c}); set <node> :: iterator it; it = q.lower_bound((node){1,2,3}); //这样就可以查找了 return 0; }
非常强力的查找方式。然后……注意重载运算符只能重载小于号。
注意lowerbound返回第一个大于等于查找键值的元素,而upperbound返回的是最后一个大于等于查找键值的元素。
(4)在set中删除元素
这些函数的用法和map基本是一样的,不加以赘述。
具体的操作也就是这些了……set同样是需要用迭代器来加以访问。
希望能帮助到大家。