0

我正在实施一种算法来选择数组的第 K 个最小元素。到目前为止,当我试图释放堆内存时,我收到了这个错误:crt 检测到应用程序在堆缓冲区结束后写入内存......

int SEQUENTIAL_SELECT(int *S , int k , int n)
{
    if(n<=Q) // sort S and return the kth element directly
    {
        qsort(S,n,sizeof(int),compare);
        return S[k];
    }
    // subdivide S into n/Q subsequences of Q elements each
    int countSets = ceil((float)n/(float)Q);

    //sort each subsequnce and determine its median
    int *medians = new int[countSets];
    for(int i=0;i<countSets;i++)
    {
        if(i==countSets-1) 
        {
            int size = Q - (n%Q);
            qsort(&S[Q*i],size,sizeof(int),compare);
            medians[i] = S[i*Q+size/2];
            continue;
        }
        qsort(&S[Q*i],Q,sizeof(int),compare);
        medians[i] = S[i*Q+Q/2]; 
    }

    // call SEQUENTIAL_SELECT recursively to find median of medians 
    int m = SEQUENTIAL_SELECT(medians,countSets/2,countSets);
    delete[] medians;
    int size = (3*n)/4;

    int* s1 = new int[size]; // contains values less than m
    int* s3 = new int[size]; // contains values graten than m

    for(int i=0;i<size;i++)
    {
        s1[i] = INT_MAX;
        s3[i] = INT_MAX;
    }
    int i1=0;
    int i2=0;
    int i3=0;
    for(int i=0;i<n;i++)
    {
        if(S[i]>m)
            s3[i3++] = S[i];
        else if(S[i]<m)
            s1[i1++] = S[i];
        else
            i2++; // count number of values equal to m
    }

    if( i1>=k )
        m = SEQUENTIAL_SELECT(s1,k,i1);
    else if( i1+i2+i3 >= k)
        m = SEQUENTIAL_SELECT(s3,k-i1-i2,i3);


    delete[] s3;
    delete[] s1;

    return m;
}
4

1 回答 1

1

@Dcoder 肯定是正确的那Q - n%q是不正确的。应该是n%Q。另外,计算size = (3*n)/4不可靠;在给定向量的情况下尝试n = 6(假设,似乎可以肯定,Q实际上是 5)[1, 2, 3, 4, 5, 0]

您可以通过简单地检查每个数组下标分配的索引值来避免让很多人关注您的代码(尽管这不会捕获 内部的分配qsort,但下面会详细介绍)。

您肯定已经想到您正在使用大量内存来执行一个简单的操作,而这实际上可以就地完成。通常避免进行就地操作的原因是您需要保留原始向量,但是您正在计算qsort就地排序的中位数,因此原始向量已经被修改。如果这是可以接受的,那么没有理由不就地执行其余的中位数算法。[1]

顺便说一句,虽然我当然不是害怕浮点计算的人之一,但完全没有理由为countSets = ceil(float(n)/float(Q)). (n + Q - 1)/Q会工作得很好。这个成语也可以有用地用于计算size,尽管我完全不确定你3n/4从哪里得到计算。


[注 1] 提示:不是连续分组,而是将向量分成五个区域,并找到每个区域的第 i元素的中值。找到后,将其与第一个区域的第 i元素交换;完成后,您的第一个区域(向量的前五分之一)包含中位数,您可以在该子向量上递归。这意味着实际上将中值代码写成一系列比较,这很乏味,但比调用qsort. 这也避免了我上面提到的退化情况,其中中位数计算错误地返回向量中的最小元素。

于 2012-11-17T15:20:01.843 回答