split_interval_map用法,高效查找与点相交的所有区间

时间:2018-04-23 20:19:54

标签: c++ boost boost-icl

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

using namespace std;
using namespace boost::icl;

int main()
{
    split_interval_map<double, int> intervals;

    intervals.add(make_pair(interval<double>::closed(0.,1.),0));
    intervals.add(make_pair(interval<double>::closed(1.,2.),1));
    intervals.add(make_pair(interval<double>::closed(3.,4.),2));
    intervals.add(make_pair(interval<double>::closed(2.,4.),3));
    intervals.add(make_pair(interval<double>::closed(1.5,3.5),4));

    std::vector<double> probes = { 0.23, 1., 1.33 , 1.57, 3.49, 3.51 };

    for(auto probe : probes)
    {
        std::cout << std::endl<< "probe " << probe << std::endl;
        auto lower = intervals.lower_bound(interval<double>::closed(probe, probe));
        auto upper = intervals.upper_bound(interval<double>::closed(probe, probe));
        while(lower != upper)
        {
            std::cout << lower->second << " ";
            ++lower;
        }
    }
}
  1. 我得到的是指数加起来。但我正在查找包含&#39; probe&#39;的区间的所有值(int s)。 (交叉点?)
  2. 我可以用std::set<int>作为值来实现这一点,但在文档中说明,这会对性能产生巨大影响。看起来像split_interval_map包含该信息,但我不知道如何检索它。
  3. 我只需要像这个例子中那样高效的查找。我不再需要交叉的间隔范围了。升力icl太重了吗?

1 个答案:

答案 0 :(得分:1)

  
      
  1. 我得到的是指数加起来。但我正在查找包含&#39; probe&#39;的区间的所有值(整数)。 (交叉点?)
  2.   

使用您选择的组合器获取所有值(共域值)组合。对于算术类型,这意味着求和。

如果你的共同域名是一个索引,那么明确的总和不是有意义的组合,你应该选择别的东西。

  

我可以使用std::set<int>作为值来实现此目的,但在文档中说明,这会对性能产生巨大影响。

与往常一样,在表现之前是正确的。如果它符合您的需求,那么它就是您所需要的。

  

似乎split_interval_map包含该信息,但我不知道如何检索它。

不使用所选的共域:如果间隔重叠,则组合器会丢失原始信息(您使用的是add,而不是set)。

  

我只需要像这个例子中那样高效的查找。我不再需要交叉的间隔范围了。升力icl太重了吗?

您可以使用equal_range代替lower_bound / upper_bound

<强> Live On Coliru

for (auto probe : { 0.23, 1., 1.33, 1.57, 3.49, 3.51 }) {
    std::cout << "\nprobe " << probe << ": ";

    for (auto& p : boost::make_iterator_range(m.equal_range(Ival::closed(probe, probe)))) {
        std::cout << p.second << " ";
    }
}

打印

probe 0.23: 
probe 1: 1 
probe 1.33: 1 
probe 1.57: 4 
probe 3.49: 4 
probe 3.51: 3 

观察:

m.add({Ival::closed(0., 1.), 0});
m.add({Ival::closed(1., 2.), 1});
m.add({Ival::closed(3., 4.), 2});

这些间隔巧妙地重叠。 [0, 1][1, 2]共有[1,1]个共同点。你的意思是left_open吗? ([0, 1)[1, 2)没有重叠。

m.add({Ival::closed(2., 4.), 3});
m.add({Ival::closed(1.5, 3.5), 4});

如果您对重叠间隔中已有的值进行组合这一事实感到惊讶,那么您的意思是替换它们吗?

m.set({Ival::closed(2., 4.), 3});
m.set({Ival::closed(1.5, 3.5), 4});

替代方案,想法:

  1. 您可以立即与探针组进行交集:

    <强> Live On Coliru

    Set probes;
    probes.insert(0.23);
    probes.insert(1.);
    probes.insert(1.33);
    probes.insert(1.57);
    probes.insert(3.49);
    probes.insert(3.51);
    std::cout << std::endl << "all: " << (m & probes) << "\n";
    

    打印:

    all: {([1,1]->1)([1.33,1.33]->1)([1.57,1.57]->4)([3.49,3.49]->4)([3.51,3.51]->3)}
    
  2. To(也许?)优化一点:

    <强> Live On Coliru

    using Map  = icl::split_interval_map<double, boost::container::flat_set<int> >;
    
  3. 如果集合很小,请考虑为该flat_set的序列类型指定small_vector:

    icl::split_interval_map<double,
        boost::container::flat_set<int, std::less<int>, 
            boost::container::small_vector<int, 4>
        > >;
    

    其他一切仍然有效: Live On Coliru

  4. 完全 OUT-OF-THE-BOX :你在建模几何区域吗?喜欢时间轴上的间隔?或者只是轴上的线段?在这种情况下,请考虑boost::geometry::index::rtree<>