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同樣是需要用迭代器來加以訪問。
希望能幫助到大家。
