优先队列使用最大堆的具体目的是什么
What is the concrete aim of using max heap for priority queue
最大堆用于优先队列,因为最大元素的提取成本低。
不过,还请大家多多包涵
我们不应该只搜索 O(N) 次的最大元素吗?
我知道提取最大值只需要 O(log N) 时间,但在此之前我们需要构建一个堆,它本身需要 O(N) 时间。
那么为什么我们要经历如此复杂的过程甚至实现堆?
此外,有些人可能会说执行重复提取最大堆是一个优势。
但是假设我们执行 k 次搜索操作,所以通过线性搜索我们得到 O(KN) ==O(N),这与堆 O(N + K) == O(N)
如果我们执行 N extract max,我们得到 O(NLogN),这比 (NN)==(N^2) 搜索操作要好。
但是我们也可以在 O(NlogN) 中对数组进行排序,然后在 O(1) 时间内提取 N ==> O(NlogN) + O(N)。
所以我的疑问是,我们真的需要堆吗?如果我们可以将堆的功能替换为更相似的过程(如果不是更好的话)。
我错过了什么,堆的真正用途是什么。
原谅我的无知和语法错误。不是母语人士,抱歉:(....
您可以使用堆在 O(n log n) 时间内对数组进行排序 在最坏的情况下(与快速排序不同,除非您实施复杂的主元选择过程不太实用)和没有额外的space(不像Mergesort,除非你实现一个复杂的就地合并,它根本不实用).
尽管混合插入和提取(例如,Dijkstra 算法、Prim 算法),堆真的很出色。
考虑混合 N
插入和 N
提取的场景。
对于一个堆,你得到 O(NlogN)
总步数。
对于天真的方法,你得到 O(N^2)
总步数。
对于排序方法(在插入时在末尾添加元素,在查询排序时)你也得到 O(N^2)
总步骤。
想一想优先级队列在现实世界中是如何使用的。您添加一些东西,拿走一些东西,再添加一些东西,提取一些东西等等。对于堆,在最坏的情况下,添加和删除都是 O(log n)。对于列表,Add 是 O(1) 或 Remove 是 O(1)。另一个是 O(n)。通常,您希望 Add 的复杂度为 O(n),以便始终对列表进行排序,而 Peek 操作的复杂度为 O(1)。
因此,给定一系列添加和删除操作,当堆中已经有 1,000 个项目时:
Operation Heap List
Add log n n
Add log n n
Remove log n 1
Add log n n
Add log n n
Add log n n
Remove log n 1
Remove log n 1
Remove log n 1
Remove log n 1
堆是 10*log(n),列表是 5n + 5。 1,000 的 log(n) 大约是 10。所以你说的是堆的 100 次操作的顺序。对于列表,您谈论的是 5,000 次操作的顺序。所以堆会快 50 倍。如果列表中有 100 万个项目,那么一个堆需要 200 次操作,列表需要 5 百万 次操作。
如果您只是想按顺序处理一堆项目,那么使用优先级队列就没有意义了。排序列表工作得很好,并且可能比构建优先级队列并逐个提取项目更快。 (尽管您最终可能会首先使用堆排序对项目进行排序。)
使用正确的工具完成工作。
最大堆用于优先队列,因为最大元素的提取成本低。
不过,还请大家多多包涵
我们不应该只搜索 O(N) 次的最大元素吗?
我知道提取最大值只需要 O(log N) 时间,但在此之前我们需要构建一个堆,它本身需要 O(N) 时间。
那么为什么我们要经历如此复杂的过程甚至实现堆?
此外,有些人可能会说执行重复提取最大堆是一个优势。
但是假设我们执行 k 次搜索操作,所以通过线性搜索我们得到 O(KN) ==O(N),这与堆 O(N + K) == O(N)
如果我们执行 N extract max,我们得到 O(NLogN),这比 (NN)==(N^2) 搜索操作要好。
但是我们也可以在 O(NlogN) 中对数组进行排序,然后在 O(1) 时间内提取 N ==> O(NlogN) + O(N)。
所以我的疑问是,我们真的需要堆吗?如果我们可以将堆的功能替换为更相似的过程(如果不是更好的话)。
我错过了什么,堆的真正用途是什么。
原谅我的无知和语法错误。不是母语人士,抱歉:(....
您可以使用堆在 O(n log n) 时间内对数组进行排序 在最坏的情况下(与快速排序不同,除非您实施复杂的主元选择过程不太实用)和没有额外的space(不像Mergesort,除非你实现一个复杂的就地合并,它根本不实用).
尽管混合插入和提取(例如,Dijkstra 算法、Prim 算法),堆真的很出色。
考虑混合 N
插入和 N
提取的场景。
对于一个堆,你得到 O(NlogN)
总步数。
对于天真的方法,你得到 O(N^2)
总步数。
对于排序方法(在插入时在末尾添加元素,在查询排序时)你也得到 O(N^2)
总步骤。
想一想优先级队列在现实世界中是如何使用的。您添加一些东西,拿走一些东西,再添加一些东西,提取一些东西等等。对于堆,在最坏的情况下,添加和删除都是 O(log n)。对于列表,Add 是 O(1) 或 Remove 是 O(1)。另一个是 O(n)。通常,您希望 Add 的复杂度为 O(n),以便始终对列表进行排序,而 Peek 操作的复杂度为 O(1)。
因此,给定一系列添加和删除操作,当堆中已经有 1,000 个项目时:
Operation Heap List
Add log n n
Add log n n
Remove log n 1
Add log n n
Add log n n
Add log n n
Remove log n 1
Remove log n 1
Remove log n 1
Remove log n 1
堆是 10*log(n),列表是 5n + 5。 1,000 的 log(n) 大约是 10。所以你说的是堆的 100 次操作的顺序。对于列表,您谈论的是 5,000 次操作的顺序。所以堆会快 50 倍。如果列表中有 100 万个项目,那么一个堆需要 200 次操作,列表需要 5 百万 次操作。
如果您只是想按顺序处理一堆项目,那么使用优先级队列就没有意义了。排序列表工作得很好,并且可能比构建优先级队列并逐个提取项目更快。 (尽管您最终可能会首先使用堆排序对项目进行排序。)
使用正确的工具完成工作。