我想要做的是有效地处理间隔。例如,在我的示例中,间隔如下所示:
[10, 20], [15, 25], [40, 100], [5, 14]
间隔是关闭的和整数,有些间隔可能会过度。我想找到给定查询的重叠间隔有效。例如,如果给出[16, 22]
:
[10, 20], [15, 25]
上述间隔应按计算间隔计算。
我目前正在编写一个基于红黑树的区间树(参考:CLRS,算法简介)。虽然找到所有重叠间隔可以是O(n),但运行时间应该更快。请注意,可以删除并插入间隔。
但是,我刚发现Boost有interval_map
和interval_set
:
http://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
适合我的目的?
答案 0 :(得分:4)
您要求的数据结构可以有效地找到重叠。这样做,通过在数据结构中存储重叠。现在你似乎在抱怨它已经这样做了。
这个例子解释了逻辑:
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。因此,如果您想强制使用更难找到重叠的结构,您可以这样做。
答案 1 :(得分:1)
我认为你可以使用interval_map<int, set<discrete_interval<int> > >
。每当您想要添加时间间隔I
时,只需将make_pair(I, II)
添加到地图中,其中II
是仅包含set
的{{1}}。因此,对于上面的示例,您可以这样做:
I
请注意,强化文档表明#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;
}
}
interval_map
std::set
std::set
的效率不高,位于this page的底部。因此,这表明您可能希望编写自己的集合概念实现,或者使用与{{1}}不同的实现。
答案 2 :(得分:1)
我尝试了boost interval_map和interval_set。它们效率很低。设置成本非常高,因为实现基本上将每个子区间(交集)映射到包含它的所有区间。
我认为基于红黑树的CLRS“算法简介”中的实现要好得多。奇怪的是,即使std :: set和std :: map基于RB树,也没有允许扩充的红黑树实现。