例說資料結構&STL(九)——map

無鞋童鞋發表於2017-07-30

1 白話map
  map是STL的一個關聯容器,它提供一對一(其中第一個可以稱為關鍵字,每個關鍵字只能在map中出現一次,第二個可能稱為該關鍵字的值)的資料處理能力。由於這個特性,它完成有可能在我們處理一對一資料的時候,在程式設計上提供快速通道。這裡說下map內部資料的組織,map是內部自建一顆紅黑樹(一種非嚴格意義上的平衡二叉樹),這顆樹具有對資料自動排序的功能,所以在map內部所有的資料都是有序的,這和資料結構set一樣,只不過map的鍵與值是不同的型別,而set中每個鍵值對是同一個值。
  map鍵與值都可以是隨意型別,例如我們想訪問學生登分系統,通過定義一個姓名對應分數的map,這樣鍵可以是string型別,而值可以是int型別,所以定義的map可以是map<string,int> score。此外我們還想在登分之前通過學號姓名的map,這樣鍵值對我們就可以分別定義為int,string型別,所以定義的map又可以是map<int,string> name
2 STL中map實戰
 2.1 包含map的標頭檔案

#include<map>

using namespace std;

 2.2 map物件宣告
  map的構造過載了好幾種建構函式,但是都是涉及記憶體分配器,所以我們就按預設定義即可:

map<int,float> map_fir;

 2.3 插入鍵值對
  由於map是自動排序的,所以鍵值對插入什麼地方無需關注,我們只要關心放入什麼資料就行。map插入鍵值對有三種方式,如下:

map<int,float> map_sed;

map_sed.insert(pair<int,float>(100 , 0.1234)); //方法一

map_sed.insert(map<int,float>::value_type(110,100.86)); //方法二

map_sed[120] = 10000; // 方法三

  以上三種用法,雖然都可以實現資料的插入,但是它們是有區別的。當然前兩種方式是一樣的,都是用insert函式插入資料。但是資料的插入涉及到集合的唯一性這個概念,即當map中有這個關鍵字時,insert操作是插入資料不了的,但是用operator[]過載的方式就不同了,它可以覆蓋以前該關鍵字對應的值。如下:

map<int,float> map_sed;

map_sed.insert(pair<int,float>(100 , 0.1234)); 
map_sed.insert(pair<int,float>(100 , 0.5555)); //該鍵值對不會更新,100鍵對應的還是0.1234值.

map_sed[110] = 50;
map_sed[110] = 10086; //110鍵對應的值會發生改變,變成10086。

 2.4 查詢鍵值對
  有時候我們希望查詢一下當前map中是否存在某一鍵值,和set一樣我們有兩種方法,如下:

map<int,float> map_thd;

map_thd.count(110); // 統計map中某一關鍵字出現的個數,注意是關鍵字,不是值

  上面程式統計110出現的個數,我們知道map中關鍵字只可以出現一次,所以返回結果要麼是1要麼是0。所以通過返回值可以確認map中是否存在該關鍵字。

map<int,float> map_for;

if(map_for.find(110)!=map_for.end()) // find()方法返回的是查詢關鍵字的迭代器,如果沒有查詢到則指向end()
    //... 

 2.5 邊界元素

map<int,float>::iterator iter1 = map_fir.lower_bound(2); //返回map中>=2的索引(迭代器),切記不是小於2的有意思

map<int,float>::iterator iter2 = map_fir.upper_bound(2); //返回map中>2的索引 

 2.6 查詢鍵值對
  關聯式容器也可以通過迭代器間接訪問每個元素,迭代器可以象徵性的看成是指標。map和其他能夠使用迭代器的容器一樣,它的迭代器是雙向的,我們可以從頭到尾(正向迭代),也可以從尾到頭(反向迭代)訪問每個資料。

#include<iterator> 

map<int,float>::iterator iter; //對應迭代器物件

//正向間接訪問
for(iter=map_fir.begin();iter!=map_fir.end();iter++)
    cout<<iter->first<<"="<<iter->second<<endl;  

  反向索引:

map<int,float>::reverse_iterator iter; //對應反向迭代器物件

//反向間接訪問
for(iter=map_fir.rbegin();iter!=map_fir.rend();iter++)
    cout<<iter->first<<"="<<iter->second<<endl;  

  上面begin()指向的是map中首元素地址,而end()指的是集合中尾部資料的下一位地址。在反向迭代器操作中,rbegin()指向的是map尾部資料,而rend()指向第一個元素前面一個位置的元素(這個元素被認為是反轉後的尾部)。此外,切記上面反轉迭代也是iter++,而不是我們想的iter- -,這個過程map內部已經幫忙轉換。
 2.7 刪除操作

map<int,float>::iterator iter;

iter = map_fir.find(1);
map_fir.erase(iter);  // 迭代器刪除某一個鍵值對

int n = map_fir.erase(1); // 關鍵字刪除,如果刪除了會返回1,否則返回0

map_fir.erase(map_fir.begin(),map_fir.end()); // 成片刪除

 2.8 其他常用操作

map<int,float> map_fir;

map_fir.swap(map_sed); // 交換所有資料,需要確保map中元素型別相同

map_fir.clear();       // 清空map_fir

map_fir.size();        // 統計map_fir中元素個數

map_fir.empty();       // 判斷map中是否為空,如果是空則返回1

3 小結
  上面介紹了map資料結構特點以及STL中包含的介面。由於map和set一樣是基於紅黑樹構建的資料結構,所以其存取,訪問等時間複雜度都為O(logn),n為集合中元素的個數。
  以上是個人學習記錄,由於能力和時間有限,如果有錯誤望讀者糾正,謝謝!
  轉載請註明出處:http://blog.csdn.net/FX677588/article/details/76375350  


  參考文獻:
  http://blog.csdn.net/it_yuan/article/details/22697205

相關文章