map的默認排序和自定義排序


STL的容器map為我們處理有序key-value形式數據提供了非常大的便利,由於內部紅黑樹結構的存儲,查找的時間復雜度為O(log2N)。

一般而言,使用map的時候直接采取map<typename A, typename B>的形式即可,map的內部實現默認使用A類型變量的升序來排序map的值。

但是有時我們需要對map的值做特殊的排序(不經其他容器的輔助),這就需要在定義map變量時做些特殊的處理。

STL中map的定義是:

1 template<class _Kty,
2     class _Ty,
3     class _Pr = less<_Kty>,
4     class _Alloc = allocator<pair<const _Kty, _Ty>>>
5     class map
6         : public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false>>
7     {    

這是一個模板類,我們的特殊處理主要改造的就是class _Pr = less<_Kty>,並且從這里我們也能看到,無論做哪種修改,排序都是針對key而言的,要實現value的自定義排序,

不是修改_Pr類型能完成的。

替換_Pr的也必須是一個類型,即至少我們要自己創建一個類型,用來做key的比較。自然,我們需要做的是重載函數調用操作符"()",一般的形式為

1 class T{
2 public:
3     bool operator()(const T& lhs, const T& rhs)const
4     {
5         ...    
6     }    
7 };

代碼需包含頭文件<algorithm>、<functional>

下面是常見的一些自定義排序:

a.對基本類型的key以降序排列

  map默認提供的是less<_Kty>類型的排序方式,閱讀STL源碼

 1 template<class _Ty = void>
 2     struct less
 3     {    // functor for operator<
 4     _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type;
 5     _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type;
 6     _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool result_type;
 7 
 8     constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
 9         {    // apply operator< to operands
10         return (_Left < _Right);
11         }
12     };

  修改上述代碼的第10行,為修改后的類型起一個自定義名字很簡單,不過STL已經為我們提供了整個類型定義:

 1 template<class _Ty = void>
 2     struct greater
 3     {    // functor for operator>
 4     _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type;
 5     _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type;
 6     _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool result_type;
 7 
 8     constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
 9         {    // apply operator> to operands
10         return (_Left > _Right);
11         }
12     };

 

  我們直接使用就行:

 1 std::map<int, int, std::greater<int>> mi;
 2     for (int i = 0; i < 5; i++)
 3     {
 4         mi[i] = i * 2;
 5     }
 6 
 7     std::for_each(mi.begin(), mi.end(), 
 8         [](const std::map<int, int, std::greater<int>>::value_type& vl) {
 9         cout << "key:" << vl.first << "  value:" << vl.second << '\n';
10     });

 

  對應的輸出為:

  

 

  這里,我們實現了按key降序排列的目的。

 b.為自定義類型的key做排序:

  自定義類型的key定義map時(使用map默認排序),我們一般都要做一件事:為自定義類型重載“<”操作符,顯然,這是為了map創建對象時可以使用less。

  因此,我們替換less<_Kty>也同樣是要做這樣的事:自定義排序規則,  比如: 

 1 class MyKey {
 2 public:
 3     MyKey(int fidx = 0, int sidx = 0)
 4         :m_firstIdx(fidx), m_secondIdx(sidx) {}
 5 
 6     int m_firstIdx;
 7     int m_secondIdx;
 8 };
 9 
10 class MyCompare{
11 public:
12     bool operator()(const MyKey& lhs, const MyKey& rhs)const
13     {
14         if (lhs.m_firstIdx > rhs.m_firstIdx)
15         {
16             return true;
17         }
18         else if (lhs.m_firstIdx == rhs.m_firstIdx)
19         {
20             return lhs.m_secondIdx > rhs.m_secondIdx;
21         }
22         return false;
23     }
24 };
25 
26 class MyCompare2 {
27 public:
28     bool operator()(const MyKey& lhs, const MyKey& rhs)const
29     {
30         return lhs.m_firstIdx > rhs.m_firstIdx;
31     }
32 };

使用MyCompare:

 1 std::map<MyKey, int, MyCompare> mi;
 2     for (int i = 0; i < 5; i++)
 3     {
 4         mi[MyKey(i * 2, i)] = i * 2;
 5     }
 6 
 7     std::for_each(mi.begin(), mi.end(), 
 8         [](const std::map<MyKey, int, MyCompare>::value_type& vl) {
 9         cout << "key:" << vl.first.m_firstIdx << "-" << vl.first.m_secondIdx << "  value:" << vl.second << '\n';
10     });

使用MyCompare2:

 1 std::map<MyKey, int, MyCompare2> mi;
 2     for (int i = 0; i < 5; i++)
 3     {
 4         mi[MyKey(i * 2, i)] = i * 2;
 5     }
 6 
 7     std::for_each(mi.begin(), mi.end(), 
 8         [](const std::map<MyKey, int, MyCompare2>::value_type& vl) {
 9         cout << "key:" << vl.first.m_firstIdx << "-" << vl.first.m_secondIdx << "  value:" << vl.second << '\n';
10     });

  以上兩種有相同的輸出:

 我們實現了自定義類型自定義排序的目的。

 

可以看到,使用map其實有很大的自由度,我們完全可以定制自己的map,為我們解決問題、精簡代碼帶來很大的便利。

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM