C++ STL中Map的按Key排序

为了实现快速查找,map内部本身就是按序存储的(比如红黑树)。在我们插入<key, value>键值对时,就会按照key的大小顺序进行存储。这也是作为key的类型必须能够进行<运算比较的原因。现在我们用string类型作为key,因此,我们的存储就是按学生姓名的字典排序储存的。

【参考代码】

  1. #include<map>  
  2. #include<string>  
  3. #include<iostream>  
  4. using namespace std;  
  5.   
  6. typedef pair<string, int> PAIR;  
  7.   
  8. ostream& operator<<(ostream& out, const PAIR& p) {  
  9.   return out << p.first << "\t" << p.second;  
  10. }  
  11.   
  12. int main() {  
  13.   map<string, int> name_score_map;  
  14.   name_score_map["LiMin"] = 90;   
  15.   name_score_map["ZiLinMi"] = 79;   
  16.   name_score_map["BoB"] = 92;   
  17.   name_score_map.insert(make_pair("Bing",99));  
  18.   name_score_map.insert(make_pair("Albert",86));  
  19.   for (map<string, int>::iterator iter = name_score_map.begin();  
  20.        iter != name_score_map.end();  
  21.        ++iter) {  
  22.     cout << *iter << endl;    //因为重定义了输出<<操作符,否则用cout << iter->first << " => " << iter->second << '\n';
  23.   }  
  24.   return 0;  
  25.  }  

【运行结果】

 

大家都知道map是stl里面的一个模板类,现在我们来看下map的定义:

 

  1. template < class Key, class T, class Compare = less<Key>,  
  2.            class Allocator = allocator<pair<const Key,T> > > class map;  


它有四个参数,其中我们比较熟悉的有两个: Key 和 Value。第四个是 Allocator,用来定义存储分配模型的,此处我们不作介绍。

 

现在我们重点看下第三个参数: class Compare = less<Key> 

这也是一个class类型的,而且提供了默认值 less<Key>。 less是stl里面的一个函数对象,那么什么是函数对象呢?

所谓的函数对象:即调用操作符的类,其对象常称为函数对象(function object),它们是行为类似函数的对象。表现出一个函数的特征,就是通过“对象名+(参数列表)”的方式使用一个 类,其实质是对operator()操作符的重载。

现在我们来看一下less的实现:

 

  1. template <class T> struct less : binary_function <T,T,bool> {  
  2.   bool operator() (const T& x, const T& y) const  
  3.     {return x<y;}  
  4. };  


它是一个带模板的struct,里面仅仅对()运算符进行了重载,实现很简单,但用起来很方便,这就是函数对象的优点所在。stl中还为四则运算等常见运算定义了这样的函数对象,与less相对的还有greater:

  1. template <class T> struct greater : binary_function <T,T,bool> {  
  2.   bool operator() (const T& x, const T& y) const  
  3.     {return x>y;}  
  4. };  


map这里指定less作为其默认比较函数(对象),所以我们通常如果不自己指定Compare,map中键值对就会按照Key的less顺序进行组织存储,因此我们就看到了上面代码输出结果是按照学生姓名的字典顺序输出的,即string的less序列。

 

我们可以在定义map的时候,指定它的第三个参数Compare,比如我们把默认的less指定为greater:

【参考代码】

  1. #include<map>  
  2. #include<string>  
  3. #include<iostream>  
  4. using namespace std;  
  5.   
  6. typedef pair<string, int> PAIR;  
  7.   
  8. ostream& operator<<(ostream& out, const PAIR& p) {  
  9.   return out << p.first << "\t" << p.second;  
  10. }  
  11.   
  12. int main() {  
  13.   map<string, int, greater<string> > name_score_map;  
  14.   name_score_map["LiMin"] = 90;   
  15.   name_score_map["ZiLinMi"] = 79;   
  16.   name_score_map["BoB"] = 92;   
  17.   name_score_map.insert(make_pair("Bing",99));  
  18.   name_score_map.insert(make_pair("Albert",86));  
  19.   for (map<string, int>::iterator iter = name_score_map.begin();  
  20.        iter != name_score_map.end();  
  21.        ++iter) {  
  22.     cout << *iter << endl;  
  23.   }  
  24.   return 0;  
  25. }  

【运行结果】

 

现在知道如何为map指定Compare类了,如果我们想自己写一个compare的类,让map按照我们想要的顺序来存储,比如,按照学生姓名的长短排序进行存储,那该怎么做呢?

 

其实很简单,只要我们自己写一个函数对象,实现想要的逻辑,定义map的时候把Compare指定为我们自己编写的这个就ok啦。

 

  1. struct CmpByKeyLength {  
  2.   bool operator()(const string& k1, const string& k2) {  
  3.     return k1.length() < k2.length();  
  4.   }  
  5. };  

 

是不是很简单!这里我们不用把它定义为模板,直接指定它的参数为string类型就可以了。

【参考代码】

  1. int main() {  
  2.   map<string, int, CmpByKeyLength> name_score_map;  
  3.   name_score_map["LiMin"] = 90;   
  4.   name_score_map["ZiLinMi"] = 79;   
  5.   name_score_map["BoB"] = 92;   
  6.   name_score_map.insert(make_pair("Bing",99));  
  7.   name_score_map.insert(make_pair("Albert",86));  
  8.   for (map<string, int>::iterator iter = name_score_map.begin();  
  9.        iter != name_score_map.end();  
  10.        ++iter) {  
  11.     cout << *iter << endl;  
  12.   }  
  13.   return 0;  
  14. }  

【运行结果】

posted on 2016-10-29 23:21  帅胡  阅读(1009)  评论(0编辑  收藏  举报

导航