在给定范围内寻找对值

时间:2019-08-27 11:08:27

标签: c++ algorithm c++11 c++14

我有一个数组或N个对(v1, v2),其中v1 <= v2。这些应该代表时间从v1开始到v2结束的事件。它们可以相等,那么事件是瞬时的。数组按开始时间v1排序。

对于给定范围(L, R),我想找到L <= v1 <= R or L <= v2 <= R所在的任何一对。这里的想法是让事件在给定范围内开始,发生或结束。

我的主要问题是效率。该数组可能包含数十万个事件。因此,只能进行遍历所有对的线性搜索。

我读了一些关于kd-tree的信息,但是它的问题是它排除了范围的边界,只会返回L <= v1 <= R AND L <= v2 <= R。也就是说,只会返回在该范围内实际发生的事件(开始和结束),而我需要开始或结束(或显然是两者)。

我还考虑过保留2个查询表(我使用double作为时间)

std::map<double, Event*> startPoints;
std::map<double, Event*> endPoints;

并在两者中使用std::find算法并合并结果。

只需寻求建议,这是一个很好的解决方案,还是有更聪明的方法。

编辑:

对此进行重新考虑,这更加复杂。这是预期结果的一个例子

  • L
|---Ev1---|     |---Ev3---|     |---Ev5---|
        |---Ev2---|     |---Ev4---|
             |               |
             L               R

在这里我想获得Ev2(在范围内结束),Ev3(在范围内发生)和Ev4(在范围内开始)

  • L
|---Ev1---|     |---Ev3---|     |---Ev5---|
        |---Ev2---|     |---Ev4---|
                    |    |
                    L    R

在这里,我想获得当前在范围内运行的Ev3,并在范围内开始运行Ev4

  • L == R:如果我想知道某个时间点发生了什么
|---Ev1---|     |---Ev3---|     |---Ev5---|
        |---Ev2---|     |---Ev4---|
             |
             LR

在这里,我只想要Ev2,因为它是当前运行的唯一Ev2。

3 个答案:

答案 0 :(得分:3)

由于您需要处理三种情况-在给定范围内开始,发生或结束,我们可以将其分为三部分。

  1. 开始:v1位于[L,R]中。
  2. 结尾:v2位于[L,R]中。

第三种情况可以表述为v1 <= R and L <= v2,但是前两种情况部分涵盖了这种情况,因此我们将使用不同的表述来避免冲突:

  1. 正在发生:v1 < L and R < v2

好吧,如果我们可以按v1对事件数组进行排序,则很容易处理对数形式的第一种情况以及报告的事件时间数。相同的技巧适用于第二种情况。

第三种情况比较棘手。让我们来画:

enter image description here

粉红色区域代表所有间隔L <= R。红点是一个间隔,绿色区域表示我们要捕获的所有可能的事件。要进行这样的捕获,可以使用k2-tree

答案 1 :(得分:1)

使用索引方法很好-例如Boost.ICL解决方案。

话虽这么说,您可以轻松地使用std::vector-即使是未排序的-我认为只要您在100.000甚至1.000.000的范围内,就应该没问题(只要您存储实际值-不存储向量中的指针,因为这样做可能会很慢)-确切的数字当然取决于您的住所。

struct MyEvent {
  double v1;//you use double for time
  double v2;
};


std::vector<MyEvent> events;

以下是使用1.000.000元素的示例:

http://coliru.stacked-crooked.com/a/9a6d90348f6915e1

搜索将在42毫秒内进行,其中包含一个比较和可选副本,而您的情况可能有些不同,因此具有可比性。

再进一步,您可以通过使用例如来以某种方式并行化搜索来获得更多功能。 std::for_each

答案 2 :(得分:-1)

std::map->查找元素复杂度为O(logn) 如果您的密钥是唯一的,并且没有内存问题,则可以使用std::unordered_map,其摊销额(O1)。 另外,您不需要创建2张地图。 std::unordered_map<double, std::pair<Event*, Event*>> StartEndPoints;。 如果您的密钥不是唯一的,则可以使用std::unordered_multimap,但是如果您的密钥将重复很多次,则查找复杂度可能会变为(On)。 我建议不要将密钥类型作为double传递。

std::hash<double> hashing.
auto temp = hashing(key). // decltype of temp will be size_t
std::unordered_map<std::size_t, std::pair<Event*, Event*>> StartEndPoints;