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