基于迭代器构造提升优先级队列

Posted

技术标签:

【中文标题】基于迭代器构造提升优先级队列【英文标题】:construct boost priority queue based on iterators 【发布时间】:2014-04-10 08:08:25 【问题描述】:

我有一个 binomial_heaps 列表,算法的每次迭代我都必须更新一些 binomial_heaps 中元素的优先级。为此,我使用了 boost binomial_heap 的更新功能。但是,我必须完全删除和重建其中一个二项式堆(随着所有优先级的变化)。而不是每次都使用推送(如果我理解正确的话,它的复杂度会是 n*log(n)),我想基于底层容器的迭代器来构建它(一种 heapify 或 make_heap 操作,它是线性时间)。这在标准 priority_queue 中似乎是可能的,但在 boost 实现中却不是。另一方面,标准版没有为我提供更新功能。有没有办法解决这个问题,我可以同时拥有两者,或者另一个支持两者的库。或者也许我的推理是,将所有元素推送到空优先级队列上会更慢,这不正确?

有些人可能会说我需要重建整个优先级队列这一事实存在严重错误,这将使优先级队列的使用完全多余。我要实现的算法是“Finding community structure in very large networks by Aaron Clauset”,作者正是这样做的(除非我没有正确解释)

(抱歉无法发布该论文的链接,因为我没有足够的声誉发布超过 2 个链接)

【问题讨论】:

您是否查看过来自 Boost Intrusive 的陷阱? boost.org/doc/libs/1_55_0/doc/html/intrusive/… - 我不知道排序语义是否是你所追求的(因为排序基本上在 (key, prio) 复合上,如果我理解正确的话) 这是一个有趣的结构。我不知道它似乎支持从迭代器构造,不幸的是在 n*log(n) 时间内,因为我猜结构更复杂。 【参考方案1】:

Clauset 等人的“快速模块化”算法。 (paper here, code here) 使用一对链接的数据结构。一方面,你有一个稀疏矩阵数据结构(它实际上只是一个邻接表,我们不是将悬挂在特定数组元素上的元素存储为链表,而是使用平衡二叉树数据结构存储它们),和一个最大堆。稀疏矩阵中的所有值(实际上是算法中潜在合并的 dQ_ij 值)也存储在最大堆中。

因此,最大堆只是一种在稀疏矩阵中找到具有最大正值的边的有效方法。一旦你有了那个边的 ij 对,你想将列(行)i 的元素“插入”到列(行)j 的元素中,然后你想删除列(行)i。因此,您不会在每次从最大堆弹出后重建整个最大堆。相反,您想从中删除一些元素(从稀疏矩阵中删除的行/列中的元素)并更新其他元素的值(j 的更新行/列中的元素)。

这就是链接数据结构有用的地方——在原始实现中,稀疏矩阵中的每个元素都存储一个指向其在最大堆中对应条目的指针,因此如果您更新稀疏矩阵中的值,您然后可以在最大堆中找到相应的元素并更新其值。一旦你这样做了,你需要重新堆化更新的堆元素,让它在堆中(递归地)向上或向下移动。类似地,如果你删除稀疏矩阵中的一个元素,你可以在堆中找到它的入口,并在其上调用删除函数。

【讨论】:

感谢您的回答和代码。不过我还有一些问题。在某些时候,您将行(列)i 合并到 j 中,这意味着您必须更新 j 中的所有元素,甚至可能必须添加一些元素(i 中的那个或不在 j 中的元素)。在您的方法 maxheap::updateItem 中,您似乎在每次更新后 reheapify 意味着这将需要 |j|log|j|当你触摸所有元素时。这就是为什么我认为为第 j 行构造一个简单的数组,然后将其重新堆成一个最大堆可能会很快(因为它是线性的 |j|)。或不?你介意我给你发邮件,因为我有更多与论文相关的问题吗?

以上是关于基于迭代器构造提升优先级队列的主要内容,如果未能解决你的问题,请参考以下文章

C++STL之优先级队列详解

使用优先队列构建赫夫曼树

初识java集合——队列

浅析PriorityBlockingQueue优先级队列原理

Java数据结构及算法实战系列012:Java队列06——数组实现的优先级阻塞队列PriorityBlockingQueue

Java数据结构及算法实战系列012:Java队列06——数组实现的优先级阻塞队列PriorityBlockingQueue