24

我有一个map,我想在地图中找到最小值(右侧)。这是我的做法:

bool compare(std::pair<std::string ,int> i, pair<std::string, int> j) {
  return i.second < j.second;
}
////////////////////////////////////////////////////
std::map<std::string, int> mymap;

mymap["key1"] = 50;
mymap["key2"] = 20;
mymap["key3"] = 100;

std::pair<char, int> min = *min_element(mymap.begin(), mymap.end(), compare); 
std::cout << "min " << min.second<< " " << std::endl;

上面的代码工作正常,我能够得到最小值。但是,当我将这段代码按如下方式放在我的类中时,它似乎不起作用:

int MyClass::getMin(std::map<std::string, int> mymap) {
  std::pair<std::string, int> min = *min_element(mymap.begin(), mymap.end(), 
                                                 (*this).compare);
                                                 // Error probably due to "this".
  return min.second; 
}

bool MyClass::compare(
    std::pair<std::string, int> i, std::pair<std::string, int> j) { 
  return i.second < j.second; 
}

我怎样才能使代码与我的班级一起工作?另外,是否有更好的解决方案不需要编写附加compare功能?

4

5 回答 5

19

在 C++11 中,您可以这样做:

auto it = min_element(pairs.begin(), pairs.end(),
                      [](decltype(pairs)::value_type& l, decltype(pairs)::value_type& r) -> bool { return l.second < r.second; });

或者把它放在一个像这样的好函数中(注意我不是模板专家;这在很多方面可能是错误的):

template<typename T>
typename T::iterator min_map_element(T& m)
{
    return min_element(m.begin(), m.end(), [](typename T::value_type& l, typename T::value_type& r) -> bool { return l.second < r.second; });
}

使用 C++14,它进一步简化为:

min_element(pairs.begin(), pairs.end(),
            [](const auto& l, const auto& r) { return l.second < r.second; });
于 2014-11-10T11:41:37.513 回答
18

你有几个选择。做到这一点的“最佳”方法是使用functor,这保证是最快的调用:

typedef std::pair<std::string, int> MyPairType;
struct CompareSecond
{
    bool operator()(const MyPairType& left, const MyPairType& right) const
    {
        return left.second < right.second;
    }
};



int MyClass::getMin(std::map<std::string, int> mymap) 
{
  std::pair<std::string, int> min 
      = *min_element(mymap.begin(), mymap.end(), CompareSecond());
  return min.second; 
}

(您也可以将CompareSecond类嵌套在MyClass.

但是,使用您现在拥有的代码,您可以轻松地对其进行修改以使其正常工作。只需创建函数static并使用正确的语法:

static bool 
MyClass::compare(std::pair<std::string, int> i, std::pair<std::string, int> j) 
{ 
  return i.second < j.second; 
}

int MyClass::getMin(std::map<std::string, int> mymap) 
{
  std::pair<std::string, int> min = *min_element(mymap.begin(), mymap.end(), 
                                                 &MyClass::compare);
  return min.second; 
}
于 2010-04-17T17:18:35.613 回答
2

我实际上还有另一个问题:如果您需要定期获得右侧值的最小值,您确定 amap是最好的结构吗?

我建议Boost.MultiIndex一般使用索引同一组对象的多种方法来解决这些问题......但如果你只需要这个“反向映射”位Boost.Bimap可能会更容易。

这样你在寻找最小值时不会有线性搜索:)

于 2010-04-18T10:25:05.360 回答
2

问题在于:

bool MyClass::compare

需要调用类的实例。也就是说,你不能只调用MyClass::compare,但你需要someInstance.compare。但是,min_element需要前者。

简单的解决方案是static

static bool MyClass::compare

// ...

min_element(mymap.begin(), mymap.end(), &MyClass::compare);

这不再需要调用实例,您的代码就可以了。不过,您可以使用仿函数使其更通用:

struct compare2nd
{
    template <typename T>
    bool operator()(const T& pLhs, const T& pRhs)
    {
        return pLhs.second < pRhs.second;
    }
};

min_element(mymap.begin(), mymap.end(), compare2nd());

所有这一切都是从每对中抓取第二个并抓住它们,适用于任何一对。它可以用于一般,但这有点太多了。

如果你需要足够的按值查找,我建议你使用 Boost 的Bimap。这是一个双向映射,所以键和值都可以用来查找。您只需获取值键映射的前面。

最后,您始终可以跟踪进入地图的最小元素。每次插入新值时,检查它是否低于当前值(这可能是指向映射对的指针,以 null 开头),如果更低,则指向新的最低值。请求最低值变得像取消引用指针一样简单。

于 2010-04-17T17:30:36.987 回答
2

C++14

正如Jonathan Geisler对Timmmm 的回答的评论中提到的,C++14允许使用类型说明符声明lambda 函数参数。auto因此,您可以缩短 Timmmm 的基于 lambda 的min_element行(并提高其可读性),如下所示:

auto it = std::min_element(std::begin(mymap), std::end(mymap),
                           [](const auto& l, const auto& r) { return l.second < r.second; });

注意 1:如果将此行放入MyClass::getMin()函数中,则必须 return it->second。但是,要考虑空地图,您应该return按如下(或类似)调整该行:

return it == mymap.end() ? -1 : it->second;

注意 2:正如Lance Diduck也提到的,您应该通过const引用您的getMin()函数来传递地图。您这样做的方式是创建整个地图的不必要副本。

Ideone 上的代码

于 2019-06-06T14:03:57.297 回答