如何找到键大于val的映射的第一个元素

时间:2013-02-27 20:14:21

标签: c++ map stl stl-algorithm upperbound

我有一个map<double,T>(说T==string),我想找到地图的第一个元素,使得密钥大于给定的数字。我查看<algorithm>并找到upper_boundlower_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;
}

6 个答案:

答案 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_boundstd::map,而不是基于范围的std::lower_boundstd::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

Here is a demo on ideone.

答案 2 :(得分:2)

重要提示:此答案解释了为什么会出现编译错误。但是,如果可用,您应该始终更喜欢算法的成员函数版本到自由函数版本,因为它们提供了更好的复杂性保证。

因此,请使用std::map::upper_bound()std::map::lower_bound。这就是说,以下解释了为什么会出现编译时错误。


sdt::lower_boundstd::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_boundmap::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&)是一个更好的主意。