查找给定开始和结束时间的并发事件数

时间:2012-05-16 00:36:43

标签: algorithm data-structures language-agnostic computational-geometry

我有大量(~10 9 )事件,其特点是开始和结束时间。有一段时间,我想知道当时有多少事件正在进行中。

在这种情况下,哪种数据结构会有所帮助?我需要快速的操作是:

  1. 插入新活动,例如{start: 100000 milliseconds, end: 100010 milliseconds}
  2. 查询给定时间的并发事件数。

  3. 更新:有人在上面放了一个计算几何标志,所以我想我应该用计算几何来重新表述。我有一组1维间隔,我想计算这些间隔中有多少与给定点相交。插入新的间隔必须很快。

4 个答案:

答案 0 :(得分:8)

您正在寻找interval tree

  • 构造:O(n log n),其中n是间隔数
  • 查询:O(m+log n),其中m是查询结果的数量,n是间隔数
  • 空间:O(n)

答案 1 :(得分:3)

只需添加其他答案,根据时间长度和所需的粒度,您可以只使用一组计数器。例如,如果时间长度为24小时且所需粒度为1毫秒,则阵列中将有86,400,000个单元。每个单元一个4字节int(足以容纳10 ^ 9),这将少于700 MB的RAM,而基于树的解决方案至少需要(8 + 8 + 4 + 4)* 10 ^ 9 = 24个RAM用于两个指针加上每个树节点两个整数(因为32位可寻址存储器不足,每个指针需要64位)。您可以使用swap,但这会大大减慢一些查询。

如果您只关心过去24小时的数据,也可以使用此解决方案,例如,将数组用作循环缓冲区。除了时间和粒度的限制外,另一个缺点是间隔的插入时间与间隔的长度成正比,因此如果间隔长度无限制,则可能会遇到麻烦。另一方面,查询是单个数组查找。

答案 2 :(得分:2)

(通过tskuzzy和Snowball扩展答案)

平衡二进制搜索树是有意义的,除了数据集的内存要求过高。除非你可以使用库,否则B-tree会更有效,尽管更复杂。

保留两棵树,其中一棵是开始时间,另一棵是结束时间。要插入事件,请将开始时间树的开始时间和结束时间树的结束时间相加。要在时间T查询活动事件的数量,搜索开始时间树以查找有多少开始时间小于T,并搜索结束时间树以查找有多少结束时间小于T.减去从开始次数开始的结束次数,也就是活动事件的数量。

插入和查询都应该花费O(log N)时间。

一些评论:

  • 您提出问题的方式,您只关心活动事件的数量,而不是哪些事件处于活动状态。这意味着您无需跟踪哪个开始时间与哪个结束时间一致!这也可以更容易地避免先前答案引用的查询中的“+ M”术语。

  • 请注意查询的确切语义。特别是,如果事件在时间T开始,则事件在时间T计为有效吗?如果它在时间T结束?这些问题的答案会影响您是否使用<或者< =在某些地方。

  • 使用“set”数据结构,因为您几乎肯定希望允许和计算重复项。也就是说,多个事件可能同时开始和/或结束。一组通常会忽略重复。你要找的是一个“multiset”(有时也称为“bag”)。

  • 许多二叉搜索树不支持开箱即用的“元素数量< T”查询。但是通过在每个节点上存储大小来添加此功能很容易。

答案 3 :(得分:0)

假设我们有一个带有 N 元素的有序集(例如,balanced binary search treeskip list)数据结构。此外,假设排序集具有 O(log N)搜索时间, O(log N)插入时间,以及 O(N)空间使用(这些是合理的假设,例如见red-black tree)。

一种可能性是有两个有序集合bystartbyend,分别按事件的开始和结束时间排序。

要查找时间t正在进行的事件数,请byend询问结束时间大于t的第一个时间间隔: O(log N )搜索操作。调用此间隔left的开始时间。现在,请bystart询问开始时间大于或等于left且小于t的时间间隔数。这是 O(log N + M),其中 M 是这样的间隔的数量。因此,搜索的总时间为 O(log N + M)

对于有序集合,插入是 O(log N),我们必须为每个有序集合执行一次。这使得插入操作的总时间 O(log N)

从头开始构建此结构只包含 N 插入操作,因此构建的总时间为 O(N log N)

每个有序集的空间使用量为 O(N),因此总空间使用量为 O(N)

要点:

  • 插入: O(日志N),其中 N 是间隔数
  • 构造: O(N log N)
  • 查询: O(日志N + M),其中 M 是结果数
  • 空格: O(N)