我想问一下以下两个问题。
top(), pop(), push()
操作的时间复杂度是多少?我在互联网上查了一下,但我找不到答案
请告诉我答案。如果您不熟悉C ++中的所有版本,请告诉我GCC C ++ 11或C ++ 14的答案。
我想针对最短路径问题实施Dijkstra's Algorithm。
让图中的number of vertex = |V|, number of edge = |E|
使用Binary Heap时,时间复杂度为O(|E| log |V|)
但使用Fibonacci Heap时,时间复杂度为O(|E| + |V| log |V|)
。
如您所见,如果图表密集,时间会有很大差异
实际上,有O(|V|^2)
算法没有使用堆,所以我也想知道是否必须实现它。
这是我使用Binary Heap实现优先级队列
insert(x)
等于push(x)
,extract()
等于top() --> pop()
。
但是std :: priority_queue比我的实现快得多。
#include <vector>
#include <algorithm>
using namespace std;
template<class T> class PriorityQueue {
private:
size_t size_; vector<T> heap;
public:
PriorityQueue() : size_(1), heap(vector<T>(1, 0)) {};
PriorityQueue(PriorityQueue& que) : size_(que.size_), heap(que.heap) {};
size_t size() { return size_ - 1; }
inline void insert(int x) {
unsigned ptr = size_++; heap.push_back(x);
while (ptr > 1) {
if (heap[ptr >> 1] < heap[ptr]) swap(heap[ptr], heap[ptr >> 1]);
ptr >>= 1;
}
}
inline int extract() {
int ret = heap[1]; unsigned ptr = 1;
while ((ptr << 1) + 1 < size_) {
ptr <<= 1;
if (heap[ptr] > heap[ptr + 1]) swap(heap[ptr >> 1], heap[ptr]);
else swap(heap[ptr + 1], heap[ptr >> 1]), ptr++;
}
heap[ptr] = heap[--size_], heap[size_] = 0;
while (ptr > 1) {
if (heap[ptr >> 1] < heap[ptr]) swap(heap[ptr], heap[ptr >> 1]);
ptr >>= 1;
}
heap.pop_back();
return ret;
}
};
编辑:这不是this question的重复。只有时间复杂性。我还想知道使用什么类型的堆。请简单告诉我。
答案 0 :(得分:4)
标准没有指定所使用的堆的具体实现,而是指定其操作的复杂性和容器的内存复杂性。操作的复杂性如下:
请注意,Fibonacci和二进制堆都符合这些要求。然而,根据我所看到的,通常实现是binary heap。
还有一个重要的评论 - 斐波那契堆确实具有更好的渐近复杂性,但其常数因子更大,因此您需要一个相对较大的图来使其值得使用Fibonacci堆而不是二进制堆。这是一个常见错误 - 更好的渐近复杂性并不意味着该算法优于任何输入的替代方案。
答案 1 :(得分:2)
@IvayloStrandjev的回答已经提到C ++标准不需要特定的实现,而是需要时间复杂度。所以这是依赖于实现的。既然你在问题中提到了GCC,我找到了this documentation of GCC about the implementation of priority queue。
基本上它表示存在多个实现:
使用的那个可以通过tag参数配置。默认标记用于配对堆。所以我猜这是GCC默认使用的那个。
修改:正如@MartinBonner在评论中指出的那样,该链接适用于__gnu_pbds::priority_queue
而不是std::priority_queue
。我以前错过了。
std::priority_queue
使用最终使用__push_heap method from bits/stl_heap.h的make_heap
函数。快速浏览代码看起来像是 Binary Heap 的实现。