在优先级队列中随机访问

时间:2017-01-09 15:47:46

标签: c++ data-structures priority-queue

我如何在优先级队列中随机访问/搜索?例如,如果有一个像q = {5,4,3,2,1}这样的优先级队列,我想直接访问第3个值,即3,我不能这样做,是否有任何进程随机访问优先队列?

2 个答案:

答案 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。推送元素意味着找到它应该插入的位置,并向前移动所有后续元素。弹出元素只是简单地读取和删除最后一个元素(backpop_back,这些是有效的)。当然,随机访问也很有效。

2-您可以使用std::multiset(或std::multimap)而不是优先级队列。它是一种树状结构,可以对事物进行排序。您可以insert代替push,然后使用begin(或rbegin)迭代器erase读取并删除第一个(或最后一个)元素。插入和查找第一个/最后一个元素是log(n)操作。数据结构允许按顺序读取所有元素,但它不提供随机访问。

3-您可以使用std::priority_queue以及std::vectorstd::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_caststd::priority_queue,因此您可以随机访问队列中的其他元素。但是,如果它适用于您的标准库的实现,它可能不会在其他人或同一个库的未来版本上,所以我不建议您这样做!根据上面的#3,使用标准库中的算法创建自己的堆类更安全。