久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

c++ 關(guān)聯(lián)容器用法詳解2(set與map)

 zgqinghai 2020-07-06

三、關(guān)聯(lián)容器

關(guān)聯(lián)容器與序列容器有著根本性的不同,,序列容器的元素是按照在容器中的位置來順序保存和訪問的,,而關(guān)聯(lián)容器的元素是按關(guān)鍵元素來保存和訪問的。關(guān)聯(lián)容器支持高效的關(guān)鍵字查找與訪問,。兩個(gè)主要的關(guān)聯(lián)容器類型是map與set,。

1.set

1.1 簡介:set里面每個(gè)元素只存有一個(gè)key,,它支持高效的關(guān)鍵字查詢操作。set對(duì)應(yīng)數(shù)學(xué)中的“集合”,。

1.2 特點(diǎn):

 

  • 儲(chǔ)存同一類型的數(shù)據(jù)元素(這點(diǎn)和vector,、queue等其他容器相同)
  • 每個(gè)元素的值都唯一(沒有重復(fù)的元素)
  • 根據(jù)元素的值自動(dòng)排列大小(有序性)
  • 無法直接修改元素
  • 高效的插入刪除操作

 

1.3 聲明:set<T> a

set<int> a;

1.4 常用函數(shù)

以下設(shè) set<T> a,其中a是T類型的set容器,。

 

表達(dá)式

返回類型

說明

a.begin()

 

返回指向第一個(gè)元素的迭代器

a.end()

 

返回指向超尾的迭代器

a.clear()

 

清空容器a

a.empty()

 

判斷容器是否為空

a.size()

 

返回當(dāng)前容器元素個(gè)數(shù)

a.count(x)

  返回容器a中元素x的個(gè)數(shù)

1.6 插入元素:

 

  • a.insert(x) :其中a為set<T>型容器,,x為T型變量
  1. set<int> a={0,1,2,9};
  2. a.insert(6);
  3. for(auto it = a.begin();it != a.end();it++) cout << *it;//輸出01269

 

  • a.insert(first,second):其中first為指向區(qū)間左側(cè)的迭代器,second為指向右側(cè)的迭代器,。作用是將first到second區(qū)間內(nèi)元素插入到a(左閉右開),。
  1. set<int> a = {0,1,2,9};
  2. set<int> b = {3,4,5};
  3. auto first = b.begin();
  4. auto second = b.end();
  5. a.insert(first,second);
  6. for(auto it = a.begin();it != a.end();it++) cout << *it;

插入元素會(huì)自動(dòng)插入到合適的位置,使整個(gè)集合有序

1.7 刪除元素:

 

  • a.erase(x):刪除建值為x的元素
  • a.erase(first,second):刪除first到second區(qū)間內(nèi)的元素(左閉右開)
  • a.erase(iterator):刪除迭代器指向的元素
  • set中的刪除操作是不進(jìn)行任何的錯(cuò)誤檢查的,,比如定位器的是否合法等等,,所以用的時(shí)候自己一定要注意。

1.8 lower_bound 和 upper_bound 迭代器:

  • lower_bound(x1):返回第一個(gè)不小于鍵參數(shù)x1的元素的迭代器
  • upper_bound(x2):返回最后一個(gè)大于鍵參數(shù)x2的元素的迭代器
  • 由以上倆個(gè)函數(shù),,可以得到一個(gè)目標(biāo)區(qū)間,,即包含集合中從'x1'到'x2'的所有元素
  1. #include<iostream>
  2. #include<set>
  3. #include<algorithm>
  4. using namespace std;
  5. int main()
  6. {
  7. set<int> a = {0,1,2,5,9};
  8. auto it2 = a.lower_bound(2);//返回指向第一個(gè)大于等于x的元素的迭代器
  9. auto it = a.upper_bound(2);//返回指向第一個(gè)大于x的元素的迭代器
  10. cout << *it2 << endl;//輸出為2
  11. cout << *it << endl;//輸出為5
  12. return 0;
  13. }

1.9 set_union() 與 set_intersection()

set_union():對(duì)集合取并集

set_union()函數(shù)接受5個(gè)迭代器參數(shù)。前兩個(gè)迭代器定義了第一個(gè)集合的區(qū)間,,接下來的倆個(gè)迭代器定義了第二個(gè)集合的區(qū)間,,最后一個(gè)迭代器是輸出迭代器,指出將結(jié)果集合復(fù)制到什么位置,。例如:要將A與B的集合復(fù)制到C中,,可以這樣寫:

  1. #include<iostream>
  2. #include<set>
  3. #include<algorithm>
  4. using namespace std;
  5. int main()
  6. {
  7. set<int> A = {1,2,3}, B= {2,4,5},C;
  8. set_union(A.begin(),A.end(),B.begin(),B.end(),
  9. insert_iterator<set<int> >(C,C.begin()));
  10. for(auto it = C.begin();it != C.end();it++)
  11. cout << *it <<" ";
  12. return 0;
  13. }

注意:

其中第五個(gè)參數(shù)不能寫C.begin(),原因有兩個(gè):首先,關(guān)聯(lián)集合將建看作常量,,所以C.begin()返回的迭代器是常量迭代器,,不能作為輸出迭代器(詳情請(qǐng)參考迭代器相關(guān)概念)。其次,,與copy()相同,,set_union()將覆蓋容器中已有的數(shù)據(jù),并且要求容器用足夠的空間容納新信息,,而C不滿足,,因?yàn)樗强盏摹?/p>

解決方法:可以創(chuàng)建一個(gè)匿名的insert_iterator,將信息復(fù)制給C。如上述代碼所為,。另一種方法如下:

  1. set_union(A.begin(),A.end(),B.begin(),B.end(),
  2. inserter(C,C.begin()));//調(diào)用inserter

set_intersection():對(duì)集合取交集,,它的接口與set_union()相同。

附:使用set_union()和set_intersection()還有另一種技巧,。由于需要五個(gè)迭代器,,看起來會(huì)很累贅和麻煩,如果多次使用會(huì)增加出錯(cuò)的幾率,,所以我們可以試試用宏定義的方法來簡化代碼,。如下:

  1. #include<iostream>
  2. #include<set>
  3. #include<algorithm>
  4. using namespace std;
  5. #define ALL(x) x.begin(),x.end()
  6. #define INS(x) inserter(x,x.begin())
  7. int main()
  8. {
  9. set<int> A = {1,2,3}, B= {2,4,5},C;
  10. set_union(ALL(A),ALL(B),INS(C));
  11. for(auto it = C.begin();it != C.end();it++)
  12. cout << *it <<" ";
  13. return 0;
  14. }

其中使用到了宏定義,。

1.10 set的幾個(gè)問題:

1)為何map和set的插入刪除效率比用其他序列容器高?

因?yàn)閷?duì)于關(guān)聯(lián)容器來說,,不需要做內(nèi)存拷貝和內(nèi)存移動(dòng),。set容器內(nèi)所有元素都是以節(jié)點(diǎn)的方式來存儲(chǔ),其節(jié)點(diǎn)結(jié)構(gòu)和鏈表差不多,,指向父節(jié)點(diǎn)和子節(jié)點(diǎn),。因此插入的時(shí)候只需要稍做變換,把節(jié)點(diǎn)的指針指向新的節(jié)點(diǎn)就可以了,。刪除的時(shí)候類似,,稍做變換后把指向刪除節(jié)點(diǎn)的指針指向其他節(jié)點(diǎn)也OK了。這里的一切操作就是指針換來換去,,和內(nèi)存移動(dòng)沒有關(guān)系,。

(2)為何每次insert之后,以前保存的iterator不會(huì)失效,?

iterator這里就相當(dāng)于指向節(jié)點(diǎn)的指針,,內(nèi)存沒有變,指向內(nèi)存的指針怎么會(huì)失效呢(當(dāng)然被刪除的那個(gè)元素本身已經(jīng)失效了),。相對(duì)于vector來說,每一次刪除和插入,,指針都有可能失效,,調(diào)用push_back在尾部插入也是如此。因?yàn)闉榱吮WC內(nèi)部數(shù)據(jù)的連續(xù)存放,,iterator指向的那塊內(nèi)存在刪除和插入過程中可能已經(jīng)被其他內(nèi)存覆蓋或者內(nèi)存已經(jīng)被釋放了,。即使時(shí)push_back的時(shí)候,容器內(nèi)部空間可能不夠,,需要一塊新的更大的內(nèi)存,,只有把以前的內(nèi)存釋放,申請(qǐng)新的更大的內(nèi)存,,復(fù)制已有的數(shù)據(jù)元素到新的內(nèi)存,,最后把需要插入的元素放到最后,那么以前的內(nèi)存指針自然就不可用了,。特別時(shí)在和find等算法在一起使用的時(shí)候,,牢記這個(gè)原則:不要使用過期的iterator。

(3)當(dāng)數(shù)據(jù)元素增多時(shí),,set的插入和搜索速度變化如何,?

如果你知道log2的關(guān)系你應(yīng)該就徹底了解這個(gè)答案。在set中查找是使用二分查找,,也就是說,,如果有16個(gè)元素,,最多需要比較4次就能找到結(jié)果,有32個(gè)元素,,最多比較5次,。那么有10000個(gè)呢?最多比較的次數(shù)為log10000,,最多為14次,,如果是20000個(gè)元素呢?最多不過15次,??匆娏税桑?dāng)數(shù)據(jù)量增大一倍的時(shí)候,,搜索次數(shù)只不過多了1次,,多了1/14的搜索時(shí)間而已。你明白這個(gè)道理后,,就可以安心往里面放入元素了,。

 

2.map

2.1 簡介:如果說set對(duì)應(yīng)數(shù)學(xué)中的“集合”,那么map對(duì)應(yīng)的就是“映射”,。map是一種key-value型容器,,其中key是關(guān)鍵字,起到索引作用,,而value就是其對(duì)應(yīng)的值,。與set不同的是它支持下標(biāo)訪問。頭文件是<map>

2.2 特點(diǎn):

 

  • 增加和刪除節(jié)點(diǎn)對(duì)迭代器的影響很小(高效的插入與刪除)
  • 快速的查找(同set)
  • 自動(dòng)建立key-value的對(duì)應(yīng),,key和value可以是任何你需要的類型
  • 可以根據(jù)key修改value的記錄
  • 支持下標(biāo)[]操作

2.3 聲明:map<T1,T2> m

其中T1是key類型,,T2是value類型,m就是一個(gè)T1-T2的key-value,。

map<string,int> m;//聲明一個(gè)key為string,,value為int的map型容器

下述代碼更清楚的解釋了map容器的特點(diǎn):

  1. #include<iostream>
  2. #include<map>
  3. using namespace std;
  4. int main()
  5. {
  6. map<string,int> m;
  7. m["abc"] = 5;
  8. m["cdf"] = 6;
  9. m["b"] = 1;
  10. for(auto it = m.begin();it != m.end();it++)
  11. cout << it->first <<" " << it->second << endl;
  12. return 0;
  13. }

在上述代碼中,m容器被按照key的字典序升序排列了,,而且我們可以通過將key當(dāng)作索引來獲取value的值,。(同時(shí)這也是一種插入方法)

2.4 插入元素:

 

  • 使用insert()函數(shù)插入pair類型的元素
  • 使用下標(biāo)操作向map容器中插入元素
  1. map<string,int> m;
  2. m.insert(make_pair("b",6));//insert插入
  3. m["a"] = 5;//使用下標(biāo)插入

2.5 刪除元素:

 

  • erase(key):刪除鍵為key的元素
  • erase(it):刪除迭代器it所指向的元素
  1. #include<iostream>
  2. #include<map>
  3. using namespace std;
  4. int main()
  5. {
  6. map<string,int> m;
  7. m.insert(make_pair("b",6));
  8. m["a"] = 5;
  9. m["c"] = 5;
  10. m["d"] = 5;
  11. m["e"] = 5;
  12. m.erase("d");
  13. auto pr = m.begin();
  14. m.erase(pr);
  15. for(auto it = m.begin();it != m.end();it++)
  16. cout << it->first <<" " << it->second << endl;
  17. return 0;
  18. }

2.6 map容器的遍歷:

 

  • 使用迭代器遍歷(代碼如上)

注:使用迭代器遍歷map容器,其中每一個(gè)元素可以看成是pair類型的,,訪問第一個(gè)位置的key值可以用it->first訪問,,第二個(gè)位置value的值可以用it->second訪問,其中it是指向該元素的迭代器,。

2.7 常用函數(shù):

下表中m為map類型的容器,,it為和m同類型的迭代器,key表示該類型的一個(gè)鍵,。

 

表達(dá)式

返回類型

說明

m.Count(key)

 

返回map中key出現(xiàn)的次數(shù)(0或1)

m.find(key)

迭代器

返回指向key位置的迭代器.若無則返回m.end()

m.insert(make_pair( ) )

 

插入一個(gè)元素(必須以pair形式插入)

m.erase(it)

 

刪除迭代器it所指向的元素

m.erase(key)

 

刪除鍵值為key的元素

m.size()

 

返回m中元素的個(gè)數(shù)

m.clear()

 

清空m容器

m.empty()

bool

判斷容器是否為空,??談t返回true

m.lower_bound(key)

迭代器

返回指向第一個(gè)鍵值不小于key的元素的迭代器

m.upper_bound(key)

迭代器

返回指向第一個(gè)鍵值大于key的元素的迭代器

3.重要例題:

題目來自UVa12096

有一個(gè)專門為了集合運(yùn)算而設(shè)計(jì)的“集合棧”計(jì)算機(jī),。該機(jī)器有一個(gè)初始為空的棧,,并且支持以下操作:

 

  • PUSH:空集“{}”入棧
  • DUP:把當(dāng)前棧頂元素復(fù)制一份后再入棧
  • UNION:出棧兩個(gè)集合,然后把二者的并集入棧
  • INTERSECT:出棧兩個(gè)集合,,然后把二者交集入棧
  • ADD:出棧兩個(gè)集合,,然后把先出棧的集合加入到后出棧的集合中,把結(jié)果入棧

每次操作后,,輸出棧頂集合的大?。丛貍€(gè)數(shù))。例如,,棧頂元素是A={ {},,{ {} } },,,下一個(gè)元素是B= { {},,  { { {} } }  },則:

 

  • UNION操作將得到{ {},,{ {} },,{ { {} } }  },輸出3
  • INTERSECT操作將得到{ {} },,輸出1
  • ADD操作將得到{ {},{ { {} } } ,{ {},{ {} } }  },輸出3

輸出不超過2000個(gè)操作,,并且保證操作均能順利進(jìn)行(不需要對(duì)空棧執(zhí)行出棧操作)

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>//set_union等函數(shù)定義在這里
  4. #include<vector>
  5. #include<set>
  6. #include<map>
  7. #include<stack>
  8. #define ALL(x) x.begin(),x.end()
  9. #define INS(x) inserter(x,x.begin()) //注意宏的括號(hào)和inserter
  10. using namespace std;
  11. typedef set<int> Set;
  12. map<Set,int> IDCache;
  13. vector<Set> setCache;
  14. int t,n;
  15. char cmd[10];
  16. int getID(Set s){
  17. if(IDCache.count(s))return IDCache[s];
  18. setCache.push_back(s); //將新集合加入Setcache
  19. return IDCache[s]=setCache.size()-1;//將ID加入map ,同時(shí)返回新分配的ID值
  20. }
  21. int main(){
  22. scanf("%d",&t);
  23. while(t--){
  24. scanf("%d",&n);
  25. // setCache.clear();
  26. stack<int> s;
  27. while(n--){
  28. scanf(" %s",&cmd);
  29. if(cmd[0]=='P')s.push(getID(Set()));
  30. else if(cmd[0]=='D')s.push(s.top());
  31. else{
  32. Set s1=setCache[s.top()];s.pop();
  33. Set s2=setCache[s.top()];s.pop();
  34. Set x;
  35. if(cmd[0]=='U')set_union(ALL(s1),ALL(s2),INS(x));
  36. if(cmd[0]=='I')set_intersection(ALL(s1),ALL(s2),INS(x));
  37. if(cmd[0]=='A'){ x=s2; x.insert(getID(s1)); }
  38. s.push(getID(x));
  39. }
  40. printf("%d\n",setCache[s.top()].size());
  41. }
  42. puts("***");
  43. }
  44. }

代碼出自:《算法競(jìng)賽入門經(jīng)典(第二版)》——?jiǎng)⑷昙?/p>

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多