用于处理未来事件查找结构(基于时间)(Lookup structure for handling f

2019-08-17 03:41发布

我在寻找一个有效的数据结构,那将让我提示的事件......也就是说,我将有一个应用程序,其中,在执行的时候,它是可能的,一个事件将引发对未来在执行点......是这样的:

  • T = 20:420秒,A发生
  • T = 25:在13秒,乙发生
  • T = 27:在735秒,C发生
  • ...

所以我想有一个数据结构,在那里我可以把在任何情况下在任何时间在未来,在那里我能得到并且(这样做)删除所有因活动......此外,再加上会,如果我能够去除虽然从数据结构的事件(因为它已被取消)......不是太重要,因为我可以简单地将其标记为已取消...

我的第一个念头是,也许做某种树的,但我想去除,由于事件的部分需要大量的再平衡的...

我正在考虑只是有一个int散列,映射是在那个时间点发生......我觉得在场景中的时间戳为null或事件的堆栈,有很多事件(可能是多个每秒 - 这正是我打算与工作),其实这毕竟不是一个坏主意...

所以我渴望听到你的输入... :)


编辑:

  • 更具体:我想在这里ñ在约100K-1M,所以我想我可能是具有约1-100次/秒...
  • 在t是没有特殊的重要性......这只是为了说明未来事件可以“排队”在任何时候...

谢谢

back2dos

Answer 1:

如果您的活动有一个明确的上限(例如没有事件不是在未来两天后),你可以简单地从有“的时间开始”按秒#索引的数组。 数组的值是在该偏移的事件列表。

清单或去除是非常有效 - 只需找到要在其中列出或切断,并获得或重新初始化数组指向索引之后偏移的时间偏移。

如果您的活动可以无限伸展到未来,然后自己用一个HashMap从偏移的事件列表的想法是最好的之一,与一捻 - 有一个排序列表(但要实现它)称为偏移,这样你就会有非常高效的查询(例如,您将不必遍历每个键离子地图)。

你并不需要从已知的偏置,以便没有与再平衡问题的列表中删除任何东西 - 你只是从HashMap的指向数组删除。

此外,它似乎从你的问题目前还不清楚是否有任何需要了解的“T” - 当引发事件的时间。 如果您需要了解它,它存储为事件的一部分。 但提到当事件应该发生的都应该相对于一些出发点绝对(如果它与无界范围内一个HashMap,你可以使用划时代秒,如果事件有界像在第一阵列解决方案,我上市,你应该而是使用“秒#自年初范围” - 例如,从开始的一天的昨天。



Answer 2:

我相信你正在寻找一个优先级队列与事件发生时被优先级(当然,较低的时间戳将是更高的优先级)的时间戳

只要一点点阐释与您的使用情况:

...在那里我可以把在任何情况下,在未来的任何时候...

你会插入到优先级队列与insertWithPriority,使用事件发生时的时间戳。 这将是O(LGN)

...并在那里我可以得到和(这样做)删除所有因活动...

你会重复调用共达(获得最低的时间戳事件)收集最多的利益的时候所有元素。

......此外,再加上会,如果我能够去除虽然从数据结构的事件(因为它已被取消)......不是太重要,因为我可以简单地将其标记为抵消了。

这将是可能的,但将是O(LGN)由于再平衡。



Answer 3:

有多大是N? 你经常需要插入和删除的项目,相比其他一切回事? 如果是这样的总执行时间超过10%,而如果N通常大于100(说)也许, 也许是要关注大O的时间。 我见过用花哨的容器算法实现优先级队列,分配迭代器,哈希映射,堆等,花费所有的时间创建和释放抽象对象,其中中位数队列长度就像三个节目。

新增:OK,因为N〜10 ^ 6,频率为100Hz的〜,你可能需要某种形式的二叉树或堆与O(日志(N))插入/删除时间。 如果你愿意投入的CPU时间的1%到这一点,这是10 ^ 6微秒* 1%/ 100 = 10 ^ 2微秒/操作。 这不应该是在所有的困难,因为如果典型的搜索深度为20,在50ns的〜每比较,即约1微秒做搜索。 只要确保保持它的简单,没有得到所有包裹在抽象数据类型。 你不应该担心太多关于时间花在分配/释放树中的节点,因为你只分配/释放每个操作一个节点。 重新平衡不必频繁地进行,就像也许只有以后每隔1000操作。 如果你能收集分批你插入,然后以随机顺序将它们插入,可能阻止树变得太不平衡。 如果你的很多事件都是同时发生,你可以噪声少量添加到时间码,以防止树的部分变得更像是一个线性表。



Answer 4:

好吧,我要感谢大家对你的答案 - 非常有趣和有益的。 :)

PriorityQueue中绝对是正确的术语我正在寻找 - 感谢。 现在,它是所有关于落实。

以下是我认为:

设N是队列的大小和M是在处理时的每个时间戳的事件(“并发”事件可以这么说)的平均量(事件的密度不会均匀地分布时,“遥远的未来” beeing多较稀疏,但随着时间推移,这个时间区域变得更加密集的(实际上,我认为最大的密度将在未来4〜12小时的地方))。 我要寻找一个可扩展解决方案,性能良好的相当大的M.我们的目标是要真正处理一秒内的M因事件,所以我想花最少的时间可能在寻找他们。

  1. 去了简单的的方法,因为提出了好几次,我将有O(日志N)的插入,这是相当不错的,我想。 处理一个时间戳的成本将是O(M *日志N),如果我是正确的,这是不那么好了。
    • 另一种方法是,有一个与事件 ,而不是单一事件列表树 。 它应该是可行的实现一些getlistForGivenStampAndCreateIfNoneExists操作那简直难跌树两次,如果没有列表中存在快一点。 但无论如何,为M的增长,这甚至不应该太大的关系。 因此插入将是为O(log N),和以前一样,和处理将在O(M +日志N),这也很好,我想。
    • 哈希的-名单-的事件的方法,我制定。 这也应该具有O(1)的插入和O(M)的处理成本,虽然这是不与散列太微不足道。 听起来很酷,其实。 还是我失去了一些东西? 当然,这也不是那么容易做的哈希表现良好,但除此之外,还有什么问题? 或者是散的问题? 维基百科指出:
      “以良好的尺寸哈希表,每个查找的平均成本(指令数量)是独立的存储在表元素的数目的许多哈希表的设计还允许任意插入和键-值对的缺失,以恒定平均(事实上,摊销)每运行成本“。
      快速基准表明,我的平台的标准执行,似乎应一致。
    • 阵列的-列表-事件的方法,通过提供DVK。 这具有O(1)插入。 现在,这是好的。 但是,如果正确地明白它具有O(M + T)的处理成本,其中T是所述阵列(时隙,如果你会数)的大小,因为从阵列切除正值线性成本。 此外,如果有一个最大时间偏移这仅适用。

其实,我想讨论的阵列的方法。 O(M + T)是不好的。 一点也不。 但是我把一些脑筋了进去,这是我想出了:

第一个想法:Lazyness

在O(T)可以通过任意因子嘎吱嘎吱下来,introducting有点lazyness的,但最终它还是留下O(T)。 但是,是多么糟糕呢? 让我们T = 2419200,这是28天。 然后,每天一次我清理它(最好,而低负荷预计)。 那会浪费阵列的不到5%。 在我的目标平台,复制操作发生在一个相当老2GHz的核心31msecs,所以它似乎一个坏主意不毕竟。

第二个想法:大块

思维一点后,我认为这种方案的:散列的间隔,间隔(即,给定的时间帧)反过来作为一个阵列的-列表-的事件。 的间隔全部相等的尺寸,优选简单的东西,如天或也许小时。

对于插入,我通过哈希(创建如果不存在)查找合适的时间间隔,并在区间,右边列表的事件(重新创建如果不存在),然后就插入,这是O(1)。

对于处理,我只是拿现在的时间间隔,过程中因事件,通过处理当前由于列表的事件,然后再处置它。 固定长度的数组的住宿,所以我们在O(M)(这是相当可以得到处理M个元素是最好的)。 一旦当前间隔被完全处理(因此如果间隔现在代表“过去”),I只是在澳处置它(1)。 我可以保持一个额外的参考当前间隔,无需看它,但我想这不会提供任何noticable改善。


在我看来,第二个优化真的是最好的解决方案,因为它是快速和绑定。 选择适合的间隔很好的尺寸允许优化内存开销与哈希查找开销。 我不知道,我是否应该担心的哈希查找的时间都没有。 对于高男,应该没有真正的问题,应该吗? 因此,我会选择间隔:1的大小,这使我回到接近3号。

我会是对任何输入真感激。



文章来源: Lookup structure for handling future events (time based)