我如何在优先级队列中随机访问/搜索?例如,如果有一个像q = {5,4,3,2,1}这样的优先级队列,我想直接访问第3个值,即3,我不能这样做,是否有任何进程随机访问优先队列?
答案 0 :(得分:8)
大多数优先级队列实现(包括C ++ std::priority_queue
类型)不支持随机访问。优先级队列背后的想法是牺牲随机访问来快速访问最小元素。
根据您尝试做的事情,您可以使用许多其他方法。如果始终想要访问队列中的第三个元素(而不是任何其他任意位置),那么它可能足够快,只需将两个元素出列,缓存它们,然后将值取列为你想要把其他两个元素放回去。
如果要在任何时间点访问第k个最小元素,其中k更大,一个选项是存储两个不同的优先级队列:一个包含k个元素的反向排序优先级队列(称之为左侧队列) )和一个保持剩余nk元素的常规优先级队列(称之为正确的队列)。要获得第k个最小元素,从左侧队列中出队(返回第k个最小元素),然后从右侧出列一个元素并向左排队以使其返回到总共k个元素。要进行入队,请检查该数字是否小于左侧队列的顶部。如果是这样,从左侧队列出列,将删除的元素排入正确的队列,然后将原始元素排入左侧。否则,排入右边。这保证了每个操作的O(log n)运行时。
如果您需要对排序序列进行真正的随机访问,请考虑使用订单统计树。这是一个扩充的二叉搜索树,支持按索引对元素进行O(log n)访问。您可以使用它来构建一个优先级队列 - 最小元素总是在索引0处。捕获(当然还有捕获)是很难找到一个好的实现和常量因素隐藏在O(log n)中的术语远远高于标准二进制堆。
答案 1 :(得分:2)
添加@templatetypedef的答案:
除非使用效率非常低的优先级队列,否则无法将元素的随机访问与优先级队列组合在一起。以下是一些选项,具体取决于您的需求:
1-效率低下的优先级队列将是您保持排序的std::vector
。推送元素意味着找到它应该插入的位置,并向前移动所有后续元素。弹出元素只是简单地读取和删除最后一个元素(back
和pop_back
,这些是有效的)。当然,随机访问也很有效。
2-您可以使用std::multiset
(或std::multimap
)而不是优先级队列。它是一种树状结构,可以对事物进行排序。您可以insert
代替push
,然后使用begin
(或rbegin
)迭代器erase
读取并删除第一个(或最后一个)元素。插入和查找第一个/最后一个元素是log(n)操作。数据结构允许按顺序读取所有元素,但它不提供随机访问。
3-您可以使用std::priority_queue
以及std::vector
和std::push_heap
算法(以及std::pop_heap
和{{}来破解您自己的push_back
版本1}} pop_back
的方法。您将获得相同的有效优先级队列,但也可以随机访问priority_queue的所有元素。它们没有排序,你只知道数组中的第一个元素是最高优先级元素,其他元素以满足堆属性的方式存储。如果您偶尔只想按顺序读取所有元素,则可以使用函数std::vector
按优先级对数组中的所有元素进行排序。函数std::sort_heap
将使您的数组返回其堆状态。
请注意,std::make_heap
默认使用std::priority_queue
来存储其数据。有可能std::vector
reinterpret_cast
到std::priority_queue
,因此您可以随机访问队列中的其他元素。但是,如果它适用于您的标准库的实现,它可能不会在其他人或同一个库的未来版本上,所以我不建议您这样做!根据上面的#3,使用标准库中的算法创建自己的堆类更安全。