如何使用最相关的项目保留大型优先级队列?

时间:2011-01-04 00:17:53

标签: c++ algorithm data-structures

在优化问题中,我在队列中保留了许多候选解决方案,我根据其优先级进行检查。

每次我处理一个候选人时,它会从队列中删除,但它会产生几个新候选人,使得候选人数呈指数级增长。为了解决这个问题,每当候选人被添加到队列中时,我都会为每个候选人分配一个相关性,如果没有更多可用的空间,我会替换(如果适当的话)最少的相关的候选人目前与新人一起排队。

为了有效地做到这一点,我保留了一个大的(固定大小)数组,其中包含候选和两个链接的间接二进制堆:一个以递减优先级顺序处理候选,另一个以递增相关性处理候选。

这对我的目的来说足够有效,并且所需的补充空间大约是4个投注/候选人,这也是合理的。然而,编码很复杂,而且看起来并不是最佳的。

我的问题是,如果您知道更合适的数据结构或更多自然方式来执行此任务而不会降低效率。

3 个答案:

答案 0 :(得分:6)

这是一个有效的解决方案,不会改变正常堆的时间或空间复杂性:

在最小堆中,每个节点都少于其子节点。在max-heap中,每个节点都大于其子节点。让我们在每个级别的最小和最大属性之间交替进行:每个奇数行小于其子级及其孙级,以及偶数行的逆。然后找到最小的节点与通常相同,找到最大的节点需要我们查看根的子节点并取最大的节点。冒泡节点(用于插入)变得有点过时,但它仍然是相同的O(logN)复杂度。

跟踪容量并弹出最小(最不相关)的节点很容易。

编辑:这似乎是标准的最小 - 最大堆!有关说明,请参阅here。有一个C实现:headersourceexample。这是一个示例图:

http://internet512.chonbuk.ac.kr/datastructure/heap/img/heap8.jpg

答案 1 :(得分:1)

“最佳”很难判断(几乎不可能)而没有分析。

有时候,“哑”算法可能是最快的,因为英特尔CPU在连续内存块上的哑阵列扫描速度非常快,特别是如果循环和数据可以适合片内。相比之下,在不适合片内的较大内存块中跳转指针可能会慢几十或几百倍。

如果“聪明”的数据结构引入了锁定,从而阻止多个线程同时进行,那么当您尝试并行化代码时,也可能会出现问题。

我建议您分析当前的最小 - 最大值方法和简单的阵列扫描(没有链接列表=更少的内存),以查看哪个表现最佳。看起来很奇怪,我看到“巧妙”的算法在实践中通过简单的阵列扫描打败了链接列表,因为更简单的方法使用更少的内存,具有更紧密的循环并且从CPU优化中获益更多。您还可以使用固定大小的数组来避免内存分配和垃圾回收问题。

您可能想要考虑的一个选项是什么解决方案是不经常修剪并每次删除更多元素。例如,在每个修剪操作中删除100个元素意味着您只需要修剪100个时间。这可能允许更加不对称的方法来添加和删除元素。

但总的来说,请记住,优化的计算机科学方法并不总是能够在当前和未来的硬件上实现最高性能的实用方法。

答案 2 :(得分:1)

如果你使用skip-lists而不是堆,那么在O(logn)中进行搜索时,你将有O(1)时间使元素出列。
另一方面,跳过列表更难实现并且使用比二进制堆更多的空间。