如何在地图中找到最小值?

Posted

技术标签:

【中文标题】如何在地图中找到最小值?【英文标题】:How can I find the minimum value in a map? 【发布时间】:2011-02-09 04:42:53 【问题描述】:

我有一个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 函数?

【问题讨论】:

getMin 函数应该通过 const 引用而不是值来传递参数。此外,当地图根本没有元素时,您会遇到问题,因此请考虑在确定 end() 未返回之前不要取消引用迭代器。 en.cppreference.com/w/cpp/algorithm/min_element 具有线性时间。所以如果标准库不支持,最好实现自己的关联容器R/B、AVL、2-3,支持最小操作。 【参考方案1】:

您有几个选择。执行此操作的“最佳”方式是使用 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; 

【讨论】:

我为你点击了格式按钮。您需要为仿函数指定模板参数或将未使用的参数传递给工厂。或者模板operator() 而不是整个班级……这是最好的方法,是的:vP。 我同意,operator() 应该以最佳实践为模板。但是,我认为代码应该说明这一点。 “指定模板参数”是什么意思?你的意思是从binary_function派生?我不认为 min_element... 需要这样做【参考方案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 开头),如果更低,则指向新的最低值。请求最低值变得像取消引用指针一样简单。

【讨论】:

【参考方案3】:

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

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

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

【讨论】:

如果我经常发现自己试图获取地图的最大/最小值,我想仍然没有严格的标准容器? @Dilip:不,没有。该标准仅提供最常见的结构;并且没有一个支持双索引。 Boost.MultiIndex 和 Boost.Bimap 相当稳定(多年),或者你必须自己做。【参考方案4】:

在 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; );

【讨论】:

我只对参数类型lr 使用auto 使我的lambda 更加成功。然而,这可能需要 C++14。【参考方案5】:

C++14

正如Jonathan Geisler's 对Timmmm's answer 的评论中提到的,C++14 允许使用auto 类型说明符声明lambda function 参数。因此,您可以缩短 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() 函数中,你必须返回 it-&gt;second。但是,要考虑空地图,您应该按如下(或类似)调整return 行:

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

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

Code on Ideone

【讨论】:

以上是关于如何在地图中找到最小值?的主要内容,如果未能解决你的问题,请参考以下文章

使用 lambda 函数在 std::unordered_map 中查找最小值

如何将地图中的值与阈值进行比较并将大于最小阈值的值放入集合中

如何在带有边界的python优化中找到全局最小值?

如何在numpy矩阵中找到最小值?

如何在有界的python优化中找到全局最小值?

如何在excel中找到多个最小值而不重复?