时间限制超过最大堆

时间:2012-11-04 08:56:48

标签: c++

我想设计一个函数来查找时间复杂度为无序的N个元素中的k个最大元素:Θ(N+klogN)在线判断。

这是一个示例:


输入

LN 1 : N K

LN 2 : N numbers

输出

LN 1 : K biggest number

LN 2 : Final heap

示例输入

10 4
17 19 26 37 30 11 5 29 32 1

示例输出

29
26 19 11 17 1 5

这是我的代码:

#include <iostream>

using namespace std;

int main(){

    int i,j,rc,temp,temp1,length,K;
    cin>>length>>K;
    int *heap = new int[length];

    for(i=0;i<length;i++) cin>>heap[i];
    for(i=length/2-1;i>=0;i--){                  //build a max heap first with Θ(N)
        while(!((i>=length/2)&&(i<length))){
            j = 2*i+1;
            rc = 2*i+2;
            if((rc<length)&&(heap[j]<heap[rc])) j=rc;
            if(heap[i]>heap[j]) break;
            temp = heap[i];
            heap[i]=heap[j];
            heap[j]=temp;
            i=j;
        }
    }
    int k,n=length;
    for(k=0;k<K;k++){                         //shiftdown k times to find k biggest 
        temp1=heap[--n];                      //numbers with Θ(klogN)
        heap[n] = heap[0];
        heap[0] = temp1;
        if(n!=0) {
            i=0;
                while(!((i>=n/2)&&(i<n))){
                     j = 2*i+1;
                    rc = 2*i+2;
                    if((rc<n)&&(heap[j]<heap[rc])) j=rc;
                    if(heap[i]>heap[j]) break;
                    temp = heap[i];
                    heap[i]=heap[j];
                    heap[j]=temp;
                    i=j;
                }
            }
        }


    cout<<heap[length-K]<<endl;
    for(i=0;i<length-K;i++)
        cout<<heap[i]<<" ";
    return 0;
}

没关系,但其中一个数据是Time Limit Exceed,我对如何解决这个问题感到很困惑。

3 个答案:

答案 0 :(得分:0)

您的筛选操作似乎不正确。那里不应该有两个嵌套循环。你应该从根开始,并与其中一个孩子交换,直到它比两者都大。外部循环for(i=n/2-1;i>=0;i--)不应该在那里(它导致每次筛选取O(n)) - 我认为你应该将i设置为0以从根开始。

编辑:你的heapify操作也太慢了:你对外部和内部循环使用相同的循环变量i,因此它会交替变大和变小。内循环应该以外循环的i开始,但不应该影响外循环下一次迭代中i的值。我建议将sift-down操作放在自己的函数中。这既可以解决这个问题,也可以避免两次扫描编码。

答案 1 :(得分:0)

我猜想有些在线judge.org比赛。你为什么不分享问题链接?

然后我们可以判断你是否真的需要heapsort,或者你是否更喜欢使用QuickSelect和良好的启发式方法。

我的猜测是,对于他们的一个测试用例,一个普通的heapsort 不足

您可能还需要添加优化,例如检查预分类数据,或者在开头和结尾反转已排序的数据(和数据部分)。避免为这些部分构建堆,但要保持原样。

尝试在巨大的反向排序列表上运行heapsort,使用大k,IIRC这是最坏的情况(对于最大堆,任何最小堆都应该是最糟糕的情况,反之亦然)。

典型的在线判断测试案例通常围绕这些已知的最坏情况进行设计。然后设置时间限制,以便即使使用非常好的优化O(n + k log n)解决方案,与真正的O(n)解决方案相比也会失败。他们只需要让k足够大。他们来自竞赛,他们希望通过给予真实的平均输入文件来挑战人们!

P.S。您堆构建似乎也太复杂了。问题是您再次增加i 。你不应该这样做。通过在while循环中增加i,可以使自下而上的堆构造再次“重新启动”多次。所以你的堆构建可能不再是O(n)

答案 2 :(得分:0)

您可能想要检查三个差异序列会发生什么:

    1. 4 2 1 2 3 4
    1. 4 2 4 3 2 1
    1. 4 2 1 1 1 1

 int NN=0;
 for(i=length/2-1;i>=0;i--){                  //build a max heap first with Θ(N)
cout << "i=" << i << "\n";
    while(!((i>=length/2)&&(i<length))){
        j = 2*i+1;
        rc = 2*i+2;
        cout << NN++ << " " << j << " " << rc << " " << i << "\n";
        if((rc<length)&&(heap[j]<heap[rc])) j=rc;
        if(heap[i]>heap[j]) break;
        temp = heap[i];
        heap[i]=heap[j];
        heap[j]=temp;
        i=j;
    }
}

在最后一种情况下,循环将稳定到j = 3; RC = 4; I = 1;

也许内循环应该使用单独的变量而不是'i'。