我有一个map<double,T>
(说T==string
),我想找到地图的第一个元素,使得密钥大于给定的数字。我查看<algorithm>
并找到upper_bound和lower_bound。
奇怪的是,我可以使用lower_bound
而不是upper_bound
获得上面的第一个,我做错了什么?
#include <iostream>
#include <map>
#include <algorithm>
#include <string>
using namespace std;
bool lte (pair<double,string> x, const double y) {
return (x.first-y)<.001;
}
bool gte (pair<double,string> x, const double y) {
return (x.first-y)>.001;
}
int main()
{
map<double,string> myMap;
myMap[10.01] = "A";
myMap[14.62] = "B";
myMap[16.33] = "C";
myMap[45.23] = "D";
myMap[0.23] = "E";
map<double,string>::iterator it;
for(it = myMap.begin(); it != myMap.end() ; it++){
cout << it->first << " => " << it->second << endl;
}
map<double,string>::iterator firstAbove_1;
firstAbove_1 = lower_bound(myMap.begin(), myMap.end(), 15., lte); //
cout << "first greater that 15 is " << firstAbove_1->second << '\n';
//map<double,string>::iterator firstAbove_2;
//firstAbove_2 = upper_bound (myMap.begin(), myMap.end(), 15., gte); // ^
//cout << "first greater that 15 is " << firstAbove_2->second << '\n';
return 0;
}
答案 0 :(得分:3)
您使用的比较功能应严格小于,不小于或等于。否则算法可能会失败。
为了提高效率,您应该使用内置于地图中的member function upper_bound
,而不是algorithm
中的{。}}。
如果由于浮点不匹配而需要考虑未命中,请将其作为后续步骤进行。
map<double,string>::iterator it;
it = myMap.upper_bound(15.0);
if (it != myMap.begin())
{
map<double,string>::iterator it2 = it;
--it2;
if (it2->first > 15.0 - 0.001)
it = it2;
}
答案 1 :(得分:2)
gte
应为
bool gte (const double y, pair<double,string> x) {
return (y-x.first)<.001;
}
因为你需要切换参数。这为您提供了所需的结果,但它并不理想,因为比较函数不是对称的。任何阅读此代码的人都需要非常关注比较的哪一方面,以了解您正在做的事情。
如果您使用lower_bound
中的成员函数upper_bound
和std::map
,而不是基于范围的std::lower_bound
和std::upper_bound
,那么您的程序将更具可读性:
firstAbove_1 = myMap.lower_bound(15.0);
firstAbove_2 = myMap.upper_bound(15.0);
以下是运行此结果的结果:
0.23 => E
10.01 => A
14.62 => B
16.33 => C
45.23 => D
first greater than 15 is C
first greater than 15 is C
答案 2 :(得分:2)
重要提示:此答案解释了为什么会出现编译错误。但是,如果可用,您应该始终更喜欢算法的成员函数版本到自由函数版本,因为它们提供了更好的复杂性保证。
因此,请使用std::map::upper_bound()
和std::map::lower_bound
。这就是说,以下解释了为什么会出现编译时错误。
sdt::lower_bound
和std::upper_bound
的参数顺序为已交换。参见C ++ 11标准的第25.4.3.1-2段:
25.4.3.1 lower_bound [lower.bound]
template<class ForwardIterator, class T, class Compare>
ForwardIterator lower_bound(
ForwardIterator first,
ForwardIterator last,
const T& value,
Compare comp
);
1 需要:[first,last]的元素e应根据表达式 e&lt;进行分区。价值或比较(e,价值)。
2 返回:[first,last]范围内的最远迭代器i,对于[first,i]范围内的任何迭代器j,以下相应条件成立: * j &LT; value或comp(* j,value)!= false 。
[...]
25.4.3.2 upper_bound [upper.bound]
template<class ForwardIterator, class T>
ForwardIterator upper_bound(
ForwardIterator first,
ForwardIterator last,
const T& value);
Compare comp
);
1 需要:[first,last]的元素e应根据表达式!(value&lt; e)或!comp(value,e)进行分区。< /强>
2 返回:[first,last]范围内最远的迭代器i,对于任何迭代器j, 范围[first,i]以下相应条件成立:!(值&lt; * j)或comp(value,* j) == false。
[...]
您应该相应地修改比较器功能:
bool lte (pair<double, string> x, const double y) {
...
}
bool gte (const double y, pair<double,string> x) {
...
}
此外,value_type
的{{1}}不是std::map<A, B>
,而是std::pair<A, B>
。为避免无用的转换和副本,我建议使用以下签名:
std::pair<A const, B>
答案 3 :(得分:1)
你的功能gte错了。它必须是
bool gte (const double y, pair<double,string> x) {
return (x.first-y)>.001;
}
答案 4 :(得分:1)
首先,最好使用map::lower_bound
和map::upper_bound
,因为它们可以在O(log n) operations
中使用。不仅O(log n) comparsions
。
无论如何,我会使用lower/upper_bound
而不使用谓词但使用值(15. + .001)
答案 5 :(得分:1)
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h: In function `_ForwardIterator std::upper_bound(_ForwardIterator, _ForwardIterator, const _Tp&, _Compare) [with _ForwardIterator = std::_Rb_tree_iterator<std::pair<const double, std::string> >, _Tp = double, _Compare = bool (*)(std::pair<double, std::string>, double)]':
a.cpp:32: instantiated from here
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:2784: error: conversion from `const double' to non-scalar type `std::pair<double, std::string>' requested
在找出问题时,stl是一个臭毛茸茸的怪物。
您的问题源于比较器通常比较相同类型的两个元素这一事实,但在此您尝试使用它来比较pair<double,string>
和double
。由于c ++中模板的奇妙神奇含义,编译器没有看到比较器使用两种不同类型作为问题的事实。
lower_bound的实现总是将map元素作为第一个参数传递,比较值作为右参数传递,所以你可以在那里使用奇怪的类型比较器。但是upper_bound会围绕参数顺序进行交换,因此您会收到此类型错误。它试图在一对应该去的地方坚持双倍。
另外,你将错误的比较器传递给upper_bound
。一般来说,你应该传递相同的“&lt;”比较两种功能。
与其他人一样,使用map::upper_bound(keytype&)
是一个更好的主意。