在c ++中提高优先级队列的时间复杂度

时间:2016-07-07 14:29:11

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

在下面的代码中,我有更长的矢量长度,但它适用于较小的长度矢量。

     long priceCalculate(vector < int > a, long k) {
        long price = 0;
        priority_queue<int>pq(a.begin(),a.end());
        while(--k>=0){
            int x = pq.top();
            price = price + x;
            pq.pop();
            pq.push(x-1);
        }
        return price;
    }

我有一系列数字。我必须添加最大数量的价格,然后将该数字减1.再次找到最大数字,依此类推。我必须重复这个过程k次。 是否有比优先级队列更好的数据结构,其时间复杂度较低?

以下是使用矢量排序的代码:

    struct mclass {
        public: bool operator()(int x, int y) {
            return (x > y);
        }
    }
    compare;
    long priceCalculate(vector < int > a, long k) {

        long price = 0;
        sort(a.begin(), a.end(), compare);
        while (--k >= 0) {
            if (a[0] > 0) {

                price = price + a[0];
                a[0] = a[0] - 1;

                sort(a.begin(), a.end(), compare);
            }
        }
        return price;
    }

但是这也会在大输入长度上给出超时。

2 个答案:

答案 0 :(得分:0)

对于矢量解决方案,您应该能够通过避免循环内的sort来获得性能。

a[0] = a[0] - 1;

您可以执行类似下面的(伪)代码而不是调用sort

tmp = 0;
for j = 1 to end-1
{
    if a[0] < a[j] 
        ++tmp
    else
        break
 }
 swap a[0], a[tmp]

将递减的值正确放置在已排序的向量中,即由于向量是从开始排序的,因此您只需要找到小于或等于递减值的第一个元素,并使用[之前的元素交换元素] 0]。这应该比必须经过整个向量的sort更快。

算法示例

// Vector after decremt
9, 10, 9, 5, 3, 2
    ^
    tmp = 1

// Vector after swap
10, 9, 9, 5, 3, 2
// Vector after decremt
9, 10, 10, 5, 3, 2
       ^
       tmp = 2

// Vector after swap
10, 10, 9, 5, 3, 2

<强>性能

我将我的方法与OP中的矢量示例进行了比较:

k = 1000
vector.size = 10000000
vector filled with random numbers in range 0..9999
compiled with g++ -O3

My approach:
    real 0.83
    user 0.78
    sys 0.05

OPs vector approach
    real 119.42
    user 119.42
    sys 0.04

答案 1 :(得分:0)

排序代码有两个性能问题:

  1. 您在每次迭代中都使用vector<>。即使您的排序算法是插入排序(在这种情况下最好),它仍然需要触摸向量中的每个位置才能声明vector<>已排序。

  2. 更糟糕的是,您要将要使用的值排序到向量的前面,要求后续的sort()调用几乎所有元素都会移位。

  3. 因此,您可以通过

    实现巨大的加速
    1. 撤消排序顺序,以便您只与vector<>的结尾进行互动。

    2. 只排序一次,然后通过从末尾扫描到正确的位置来更新vector<>,然后在那里插入新值。

    3. 您还可以仔细查看您的算法正在做什么:它只在vector<>的尾部运行,它具有常量值,从中删除条目,并重新插入它们,递减1,在它的前面。我认为您应该能够使用这些知识显着简化算法,从而实现更显着的加速。最后,您可以完全从vector<>删除尾部:它的长度和值完全描述它,并且可以在一次操作中操纵其所有元素。一旦你通过优化它,你的算法应该没有时间......