【问题标题】:Can I do this with Boost interval_map?我可以用 Boost interval_map 做到这一点吗?
【发布时间】:2023-03-28 14:15:01
【问题描述】:

我想做的是有效地处理间隔。例如,在我的示例中,间隔如下所示:

[10, 20], [15, 25], [40, 100], [5, 14]

区间是闭整数,有些区间可能会重叠。我想有效地找到给定查询的重叠间隔。例如,如果给定[16, 22]

[10, 20], [15, 25]

上述区间应计算为重叠区间。

我目前正在编写基于红黑树的区间树(参考:CLRS,算法简介)。虽然找到所有个重叠区间可能是 O(n),但运行时间应该更快。请注意,间隔可以删除和插入。


不过,我刚刚发现Boost有interval_mapinterval_sethttp://www.boost.org/doc/libs/1_46_1/libs/icl/doc/html/index.html

我试过了,但这种行为对我来说很奇怪。例如,如果先插入[2, 7],然后插入[3, 8],则生成的映射将具有[2, 3)[3, 7](7, 8]。也就是说,当插入一个新的区间时,会自动完成分割。

我可以关闭此功能吗?或者,Boost 的 interval_map 是否适合我的目的?

【问题讨论】:

    标签: c++ algorithm boost data-structures boost-icl


    【解决方案1】:

    您要求一种可以有效发现重叠的数据结构。这是通过在数据结构中存储重叠来实现的。现在你似乎在抱怨它已经这样做了。

    这个例子解释了逻辑:

    typedef std::set<string> guests;
    interval_map<time, guests> party;
    party += make_pair(interval<time>::right_open(time("20:00"), time("22:00")),
    guests("Mary"));
    party += make_pair(interval<time>::right_open(time("21:00"), time("23:00")),
    guests("Harry")); 
    // party now contains
    [20:00, 21:00)->{"Mary"} 
    [21:00, 22:00)->{"Harry","Mary"} //guest sets aggregated on overlap
    [22:00, 23:00)->{"Harry"}
    

    当您添加两个重叠区间时,您实际上创建了三个具有不同属性的区间。重叠在两个原始间隔中,使其成为与任一原始间隔在逻辑上不同的间隔。并且两个原始间隔现在跨越具有不同属性的时间(一些与原始重叠,一些不重叠)。这种拆分可以有效地找到重叠,因为它们是地图中自己的间隔。

    无论如何,Boost 确实允许您选择interval combining style。因此,如果您想强制使用一种难以找到重叠的结构,您可以这样做。

    【讨论】:

    • 谢谢,但我需要保持原来的间隔。所有支持的加入操作都会破坏原始间隔。谢谢你!
    • 原来的间隔还在。如果你看一下这个例子,你可以很容易地看到“玛丽”的间隔是 20-22。它们只是以一种使重叠有效的方式编码。
    • 我知道这如何满足 OPs 的要求,但任何人都可以解释为什么 Boost 文档会说:注意我们使用字符串集的间隔映射来引入 interval_maps,因为它具有教学优势。派对示例用于立即访问区间图和重叠聚合的基本思想。对于现实世界的应用程序,不一定建议使用一组 interval_map。它与 std::sets 的 std::map 具有相同的效率问题。
    【解决方案2】:

    我尝试了 boost interval_map 和 interval_set。他们非常低效。设置成本非常高,因为实现基本上将每个子区间(交点)映射到包含它的所有区间。

    我认为基于红黑树的CLRS“算法介绍”中的实现要好得多。奇怪的是,没有允许扩充的红黑树实现,即使 std::set 和 std::map 基于 RB 树。

    【讨论】:

      【解决方案3】:

      我认为您可以使用interval_map&lt;int, set&lt;discrete_interval&lt;int&gt; &gt; &gt;。每当您想添加区间I 时,只需将make_pair(I, II) 添加到地图中,其中II 是一个仅包含Iset。所以对于上面的例子,你会这样做:

      #include <iostream>
      #include <boost/icl/interval_map.hpp>
      
      using namespace boost::icl;
      
      typedef std::set<discrete_interval<int> > intervals;
      
      intervals singleton(const discrete_interval<int> &value) {
          intervals result = { value };
          return result;
      }
      
      int main() {
          interval_map<int, intervals> mymap;
          discrete_interval<int> i1 = discrete_interval<int>(2, 7);
          discrete_interval<int> i2 = discrete_interval<int>(3, 8);
          mymap.add(make_pair(i1, singleton(i1)));
          mymap.add(make_pair(i2, singleton(i2)));
      
          for (int i = 0; i < 10; ++i) {
              std::cout << "i: " << i << ", intervals: " << mymap(i) << std::endl;
          }
      }
      

      请注意,boost 文档表明 std::sets 的 interval_map 不是特别有效,位于 this page 的底部。因此,这表明您可能想要编写自己的集合概念实现,或者使用与 std::set 不同的实现。

      【讨论】:

      • 我试过这段代码,它似乎没有编译。这是错误:'operator+=' 不匹配(操作数类型是 'boost::icl::interval_map >' 和 'std::pair<:icl ::closed_interval>, boost::icl::closed_interval >') mymap += make_pair(i1, i1);
      • 啊,谢谢——我想我应该在某个地方放一套。将编辑。
      • 实际上,如果有一个编译示例,我将不胜感激。请参阅我的问题:stackoverflow.com/questions/20387669/using-boost-interval-map/…
      • 嗯 - 你叫我出来,我活该。我假设页面上较高的代码实际上可以工作,然后对其进行了调整;但是现在我已经重写了示例并实际编译并运行了它。
      • “编译运行”是指成功还是不成功?
      猜你喜欢
      • 2015-04-11
      • 1970-01-01
      • 2011-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多