最近都在学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个模板参数的下场了