繁体   English   中英

如何以特定方式在c ++ STL中查找?

[英]How to find in c++ STL in a specific manner?

map< pair<int,int> , int > m ;

这里pair.firstpair.second是正数, pair.second >= pair.first

我想找到映射m所有迭代器,以便针对给定的键。 Key是位于对之间的整数,例如key为2,对为[2,5][1,2]等。
例如m[1,3] = 10 , m[3,5] = 6 , m[1,8] = 9 , m[7,8] = 15则当我搜索m.find(3)时返回m[1,3]m[1,8]m[3,5]迭代器。如果没有键,则返回m.end()

我不确定为什么要这样做,但是现在Boost Boost Interval Container库已经足够了。

假设你也许是想跟踪映射值的 (总和)为一个特定的点,你可以简单地套用一个分裂风格结合到你的输入数据和利润:

生活在Coliru

#include <boost/icl/split_interval_map.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>

namespace icl = boost::icl;

int main() {
    using Map  = icl::split_interval_map<int, int>;
    using Ival = Map::interval_type;
    Map m;
    m.add({Ival::closed(1,3), 10});
    m.add({Ival::closed(3,5), 6});
    m.add({Ival::closed(1,8), 9});
    m.add({Ival::closed(7,8), 15});

    for (auto e : m) std::cout << e.first << " -> " << e.second << "\n";

    std::cout << "------------------------------\n";

    for (auto e : boost::make_iterator_range(m.equal_range(Ival::closed(3,3))))
        std::cout << e.first << " -> " << e.second << "\n";
}

这将告诉我们:

[1,3) -> 19
[3,3] -> 25
(3,5] -> 15
(5,7) -> 9
[7,8] -> 24
------------------------------
[3,3] -> 25

注意如何

  • 合并非常准确地反映出, [3,3]是唯一同时与输入数据中的[1,3][3,5]一致的点,因此,我们在组合集( [1,3)[3,3](3,5] )。
  • 另请注意,针对这一点的查询如何针对您感兴趣的所有三个时间间隔正确返回10+6+9的总和。

这有什么用?

因此,您看到我将问题的焦点从“如何?”转移了。 到“什么?”。 通常,它有助于陈述代码的目标,而不是特定的机制。

当然,如果您对平均值,最小值或最大值而不是总和感兴趣,那么您可能会发现自己正在编写一些自定义合并策略。

奖励如果您愿意,这里至少可以使用Boost Icl: Live On Coliru来写出解决OP中出现的问题的解决方案。 尽管它不是特别有效,但它简单而强大。

无法避免从地图开始进行线性搜索,因为如果第一个元素为{0,INT_MAX},则它匹配并且您想要的元素不一定在连续范围内,例如,如果您有{1,3 },{2,2} {3,5}仅在键为3时才需要第一个和最后一个元素。

当您到达first大于键的元素时,可以停止搜索。

像这样(未经测试):

typedef map< pair<int,int> , int > Map;

std::vector<Map::iterator>
find(int key, const Map& m)
{
  std::vector<Map::iterator> matches;
  for (Map::iterator it = m.begin(), end = m.end(); it != end && key <= it->first; ++it)
  {
    if (it.first >= key && key <= it.second)
      matches.push_back(it);
  }
  return matches;
}

您可以将其转换为函子并使用find_if但我不确定是否值得。

如果只希望每个调用返回一个迭代器:

typedef map< pair<int,int> , int > Map;

Map::iterator
find(int key, const Map& m, Map::iterator it)
{
  for (Map::iterator end = m.end(); it != end && key <= it->first; ++it)
  {
    if (it.first >= key && key <= it.second)
      return it;
  }
  return m.end();
}

Map::iterator
find(int key, const Map& m)
{ return find(key, m, m.begin()); }

我认为可以代替(迭代器)存储(并使用)地图的相应键。 如果是这样,那么代码可能看起来像

#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include <utility>

int main() 
{
    std::map<std::pair<int, int>, int> m;
    m[{ 1, 3}] = 10; 
    m[{ 3, 5}] = 6;
    m[{ 7, 8}] = 15;

    typedef std::map<std::pair<int, int>, int>::value_type value_type;
    typedef std::map<std::pair<int, int>, int>::key_type key_type;

    int search;

    auto in_range = [&search]( const value_type &value )
    {
        return value.first.first <= search && search <= value.first.second; 
    };

    search = 3;

    std::vector<key_type> v;
    v.reserve( std::count_if( m.begin(), m.end(), in_range ) );

    for ( const auto &p : m )
    {
        if ( in_range( p ) ) v.push_back( p.first );
    }

    for ( const auto &p : v ) 
    {
        std::cout << "[ " << p.first << ", " << p.second << " ]" << std::endl;
    }

    return 0;
}

输出是

[ 1, 3 ]
[ 3, 5 ]

考虑到key.first小于或等于key.second,其中key是映射的键。

如果您只需要迭代器即可访问映射中找到的下一个值,则可以使用std :: find_if算法,如下所示:

int key=2;
map<pair<int,int>, int>::iterator it =std::find_if(m.begin(),m.end(),
                         [key](pair<pair<int,int>,int> entry)
                         {
                           return (entry.first.first <= key) 
                                  && (entry.first.second >= key);
                         }
                         );

cout << "the next value is: [" << it->first.first << "/";
cout << it->first.second << "] " << it->second << endl;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM