STL的map容器將第3個模板參數設爲less_equal或greater_equal會怎樣?

最近都在學Linux系統編程,用C就足矣,有段時間沒碰C++了,因而實現些算法練手。node

實現多項式乘法的時候發現有幾項沒有合併同類項,最終調試到這一步時發現了問題。ios

res是map類型,用find查找key爲1991的key-value時,結果獲得的倒是<12,1>的key-value。c++

因而轉去看那段代碼,發現了問題。由於map默認是升序排列,我最後須要打印的多項式是按照冪次數(即這裏res的key)降序排列,因此我須要設置map的第3個模板參數,可是因爲代碼補全我沒確認就選擇了。算法

map<int, int, std::greater_equal<int>> res;

個人本意是用std::greater<int>,結果補全的時候沒仔細看,補全成了greater_equal<int>,也就是大於或等於。編程

C++的map的常見實現是內部維護了一顆紅黑樹(二叉平衡樹)從而獲得按照key的大小排列的key-value,由於二叉平衡樹默認是左子節點<父節點<右子節點,而怎麼比較節點之間的大小則是個問題,由於節點能夠是類而不是基本數據類型(int、double等等),因而就有了map第3個模板參數,默認是less<>,也就是對基本數據類型來講是,而對類(設爲Object)來講則是它的bool operator < (const Object&) const方法。數組

因此關鍵是對象之間的operator < 的定義。相似地,在進行find()等須要查找的操做時,取決於對象之間的operator == 的定義less

gdb跟蹤find()函數的運行過程到達關鍵代碼函數

2288      template<typename _Key, typename _Val, typename _KeyOfValue,
2289               typename _Compare, typename _Alloc>
2290        typename _Rb_tree<_Key, _Val, _KeyOfValue,
2291                  _Compare, _Alloc>::iterator
2292        _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2293        find(const _Key& __k)
2294        {
2295          iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k);
2296          return (__j == end()
(gdb) 
2297              || _M_impl._M_key_compare(__k,
2298                        _S_key(__j._M_node))) ? end() : __j;
2299        }

含義很好理解,經過_M_lower_bound函數返回迭代器__j,而後若__j爲end()或者對__k(插入節點)和__j(下界節點)的節點值的比較爲真,則返回end(),不然返回__j。_M_key_compare即咱們傳入map的第三個模板參數,後面記爲operator < (),對int默認定義是:less<int>,即符合如下規則測試

operator < (1,2):真;operator < (1,1):假;operator < (1,0):假。spa

_M_lower_bound能夠參照STL算法lower_bound的定義(http://www.cplusplus.com/reference/algorithm/lower_bound/)

Returns an iterator pointing to the first element in the range [first,last) which does not compare less than val.

返回按照operator<()排好的升序數組中第1個不小於val的數,也就是第1個operator < (數組元素,待查找值)爲假的數,示例以下:

【case 1】數組:1 2 4 5;查找:3。   1<3:真;2<3:真;4<3:假。 ——返回4,對應:查找失敗

【case 2】數組:1 2 3 5;查找:3。   1<3:真;2<3:真;3<3:假。 ——返回3,對應:查找成功

回顧剛纔的代碼,咱們能夠看到_M_impl._M_key_compare(__k, _S_key(__j._M_node))的意義在哪

operator < (查找值,lower_bound的返回值)爲真對應的是上面的case 1,也就是查找失敗,find()查找失敗會返回end()

 

回到map上來,也就是說,map調用find()方法不須要operator==的定義,只須要operator<的定義便可。

那麼假如operator<被定義爲less_equal而不是less呢?

case 1不變,咱們從新考慮上面的case 2:1<3:真;2<3:真;3<3:真;5<3:假,返回5。

——等等,3<3爲何爲真?注意,此時的<已經不是數學意義上的小於(<)了,而是調用了operator<(),operator<()被賦予數學意義上的小於或等於(<=)的意義,那麼3<3的結果就等同於數學意義上的3<=3。

也就是說,模板參數設爲less_equal時,lower_bound永遠不會返回和查找值同樣的值,也就是說,find()函數永遠不會返回end(),即查找失敗。

(greater_equal和less_equal相似,只不過升序改爲降序)

最後給個測試程序來證實個人結論

#include <iostream>
#include <map>
#include <functional>
using namespace std;

int main()
{
    map<int, int, greater_equal<int>> m;
    int key = 250;
    m.emplace(key, 0);

    for (int val = 100; val < 120; val++)
    {
        // 若m中不存在key則將<key,val>添加進去
        if (m.find(key) == m.end())
            m.emplace(key, val);
    }

    // 顯示map的數據
    for (auto& x : m)
        cout << x.first << "=>" << x.second << endl;

    return 0;
}
$ g++ test.cpp -std=c++11
$ ./a.out 
250=>119
250=>118
250=>117
250=>116
250=>115
250=>114
250=>113
250=>112
250=>111
250=>110
250=>109
250=>108
250=>107
250=>106
250=>105
250=>104
250=>103
250=>102
250=>101
250=>100
250=>0

map中一個key對應儘量多個value,這就是使用less_equal或greater_equal做爲map第3個模板參數的下場了

相關文章
相關標籤/搜索