详解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 {
|
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最大的区别。