在c ++中使用什么类型的堆和std :: priority_queue的时间复杂度?

时间:2016-12-20 08:22:08

标签: c++ algorithm c++11 priority-queue dijkstra

我想知道什么

我想问一下以下两个问题。

  • 在C ++中std :: priority_queue中使用了什么类型的堆?
  • C ++中std :: priority_queue的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的重复。只有时间复杂性。我还想知道使用什么类型的堆。请简单告诉我。

2 个答案:

答案 0 :(得分:4)

标准没有指定所使用的堆的具体实现,而是指定其操作的复杂性和容器的内存复杂性。操作的复杂性如下:

  • top - O(1)
  • pop - O(log(n))
  • push - O(log(n))
  • 内存复杂度 - O(n)

请注意,Fibonacci和二进制堆都符合这些要求。然而,根据我所看到的,通常实现是binary heap

还有一个重要的评论 - 斐波那契堆确实具有更好的渐近复杂性,但其常数因子更大,因此您需要一个相对较大的图来使其值得使用Fibonacci堆而不是二进制堆。这是一个常见错误 - 更好的渐近复杂性并不意味着该算法优于任何输入的替代方案。

答案 1 :(得分:2)

@IvayloStrandjev的回答已经提到C ++标准不需要特定的实现,而是需要时间复杂度。所以这是依赖于实现的。既然你在问题中提到了GCC,我找到了this documentation of GCC about the implementation of priority queue

基本上它表示存在多个实现:

  • Paring Heap
  • Binary Heap
  • 二项式堆
  • RC Binomial Heap
  • 薄堆

使用的那个可以通过tag参数配置。默认标记用于配对堆。所以我猜这是GCC默认使用的那个。

修改:正如@MartinBonner在评论中指出的那样,该链接适用于__gnu_pbds::priority_queue而不是std::priority_queue。我以前错过了。

std::priority_queue使用最终使用__push_heap method from bits/stl_heap.hmake_heap函数。快速浏览代码看起来像是 Binary Heap 的实现。