詳解map、multimap、unordered_map、unordered_multimap

兔美醬xz發表於2015-02-22

詳解map、multimap、unordered_map、unordered_multimap

相信有不少同學和我一樣剛接觸C++ STL,被其深深吸引。但是想弄懂每個模板類不是一個容易事。大家應該對vector、list、stack、queue等類比較瞭解了,所以今天詳細介紹下幾個很常用很強大但有點不太好懂的類map、multimap、unordered_map、unordered_multimap。乍一看都差不多都是什麼map,但這肯定有所不同。下面就在一個一個講解的同時,讓大家瞭解這四個類的使用,以及不同之處。

map

1)  從一個簡單的例子開始

2)      #include<map>

3)      #include<iostream>

4)      using namespace std;

5)       

6)      int main()

7)      {

8)          map<char,int> msi;

9)          //map::operator[]

10)      msi['x'] = 3;

11)      msi['z'] = 3;

12)      msi['g'] = 2;

13)      msi['y'] = 1;

14)      //map::at()

15)      auto beg = msi.begin();

16)      for(; beg !=msi.end();beg++){

17)          cout<<msi.at(beg->first)<<" ";

18)      }

19)      cout<<endl;

20)      return 1;

21)  }

 

結果:

2 3 1 3

程式碼分析:

l map::operator[]

mapped_type& operator[] (const key_type& k);
mapped_type& operator[] (key_type&& k);

該函式通過呼叫mak_pair函式將k,v作為一個kv對,在通過insert函式按照k將v插入map中。

l map::at

mapped_type& at (const key_type& k);
const mapped_type& at (const key_type& k) const;
該函式通過k來找到v值。
l  從結果看出,列印是按照k值遞增來列印v值的。

2) 從例子1)繼續

我們對例子1中的程式碼進行下修改。

1)      #include<map>

2)      #include<iostream>

3)      using namespace std;

4)       

5)      int main()

6)      {

7)          map<char,int> msi;

8)          //map::operator[]

9)          msi['x'] = 3;

10)      msi['x'] = 4;  //這裡修改了

11)      msi['g'] = 2;

12)      msi['y'] = 1;

13)      //map::at()

14)      auto beg = msi.begin();

15)      for(; beg !=msi.end();beg++){

16)          cout<<msi.at(beg->first)<<" ";

17)      }

18)      cout<<endl;

19)      return 1;

20)  }

結果:

2 4 1

程式碼分析:

l 這裡出現了重複key值x,那麼是不是x/3對就被覆蓋了呢????因此只列印出2 41!!!!!

 

3) 從例子2)繼續

1)      int main()

2)      {

3)          map<char,int> msi;

4)          //map::operator[]

5)          msi['x'] = 3;

6)          msi['x'] = 4;

7)          msi['g'] = 2;

8)          msi['y'] = 1;

9)          //map::at()

10)      auto beg = msi.begin();

11)      for(; beg !=msi.end();beg++){

12)          cout<<msi.at(beg->first)<<" ";

13)      }

14)      cout<<endl;

15)   

16)      auto get = msi.equal_range('x');

17)      auto skbeg = get.first;

18)      auto skend = get.second;

19)      for(; skbeg!=skend; skbeg++){

20)          cout<<skbeg->first<<":"<<skbeg->second<<" ";

21)      }

22)      cout<<endl;

23)   

24)      return 1;

25)  }

結果:

2 4 1

x:4

 程式碼分析:

l map::equal_range

pair<const_iterator,const_iterator> equal_range (const key_type& k) const;
pair<iterator,iterator>             equal_range (const key_type& k);

按照reference中的意思這個函式應該是返回包含k的element的上下界,但是我們並沒有列印出,x:3 x:4。所以呢,嗯我們得出一個結論在map中k和v是一對一的關係,不能出現一個k對應多個v值的情況。

4) OK繼續

1)      int main()

2)      {

3)          map<char,int> msi;

4)          //map::operator[]

5)          msi['c'] = 3;

6)          msi['h'] = 5;

7)          msi['b'] = 2;

8)          msi['a'] = 1;

9)       

10)      //insert g

11)      msi.insert(pair<char,int>('g',4));

12)      //copy map

13)      map<char,int> newmap;

14)      newmap.insert(msi.begin(), msi.find('g'));

15)      //map::at()

16)      auto beg = msi.begin();

17)      for(; beg !=msi.end();beg++){

18)          cout<<beg->first<<"->"<<msi.at(beg->first)<<" ";

19)      }

20)      cout<<endl;

21)   

22)      auto newbeg = newmap.begin();

23)      for(; newbeg !=newmap.end();newbeg++)

24)          cout<<newbeg->first<<"->"<<newmap.at(newbeg->first)<<" ";

25)      cout<<endl;

26)      /*auto get = msi.equal_range('x');

27)      auto skbeg = get.first;

28)      auto skend = get.second;

29)      for(; skbeg!=skend; skbeg++){

30)          cout<<skbeg->first<<":"<<skbeg->second<<" ";

31)      }*/

32)   

33)      cout<<endl;

34)   

35)      return 1;

36)  }

結果:

a->1 b->2 c->3 g->4 h->5

a->1 b->2 c->3

程式碼分析:

l map::insert

template <class P> pair<iterator,bool> insert (P&& val);
template <class InputIterator>
void insert (InputIterator first, InputIterator last);

這裡分別使用了這兩種insert函式,其中第一個我們將一個pair物件作為一個element存入map;第二個我們將msi中從開始到g以前的element存入了newmap中。

4) TBC

還有些沒有介紹到的成員函式,我想就在另外幾個類中介紹吧,其實都很簡單…

 

multimap

1)    直奔主題

1)      #include<map>

2)      #include<iostream>

3)      #include<string>

4)      using namespace std;

5)       

6)      bool cmp(const string &a, const string &b)

7)      {

8)          return a.compare(b)>0?true:false;

9)      }

10)   

11)  int main()

12)  {

13)      bool (*cmp_pt) (const string&, const string&) = cmp;

14)      multimap<string, int, bool(*) (const string&, const string&)> mci(cmp_pt); //降序

15)      mci.insert(pair<string,int>("bb",2));

16)      mci.insert(pair<string,int>("aa",1));

17)      mci.insert(pair<string,int>("cc",3));

18)      mci.insert(pair<string,int>("gg",6));

19)      mci.insert(pair<string,int>("cc",5));//重複

20)   

21)      auto beg = mci.begin();

22)      for(;beg!=mci.end();beg++){

23)          cout<<beg->first<<"->"<<beg->second<<" ";

24)      }

25)      cout<<endl;

26)      auto skget = mci.equal_range("cc");

27)      auto skbeg = skget.first;

28)      auto skend = skget.second;

29)      for(;skbeg!=skend;skbeg++ )

30)          cout<<skbeg->first<<"->"<<skbeg->second<<" ";

31)      cout<<endl;

32)  }

結果:

gg->6 cc->3 cc->5 bb->2 aa->1

cc->3 cc->5

程式碼分析:

l 降序輸出

這裡有兩種方法,一種是函式指標,一種是類。這裡採用的前者。類方法更加簡單,只需要過載operator()即可,如下所示。

struct classcomp {

  bool operator() (const char& lhs, const char& rhs) const

  {return lhs<rhs;}

};

std::multimap<char,int,classcomp> fourth;

l 初始化資料

資料不能通過operator[]給予嘍~,沒這個成員函式。

l  重點來了

可以發現儘管加入了重複鍵值cc/5,但是列印的時候我們依然輸出了重複的鍵值對,因此我們可以說multimap和map的一個最大的區別就是,multimap可以實現一對多的儲存方式!!!!!!!!

 

unordered_multimap

1)  依然直奔主題

1)      #include<iostream>

2)      #include<unordered_map>

3)      using namespace std;

4)       

5)      int main()

6)      {

7)          unordered_multimap<char,int> umci,insertum={ {'b',12},{'w',11} };

8)          umci.insert(make_pair('d',5));

9)          umci.insert(pair<char,int>('a',1));

10)      umci.insert(make_pair('b',2));

11)      umci.insert(make_pair('g',8));

12)      umci.insert(insertum.begin(),insertum.end());

13)   

14)      auto beg = umci.begin();

15)      for(;beg!=umci.end();beg++)

16)          cout<<beg->first<<"->"<<beg->second<<" ";

17)      cout<<endl;

18)   

19)      return 1;

20)  }

結果:

g->8 b->12 b->2 w->11 a->1 d->5

程式碼分析:

l  無序儲存

可以明顯的看出unordered_multimap的無序儲存特點,這是其與multimap最大的區別。


相關文章