我正在实现一种算法来选择数组的第 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;
}
最佳答案
@Dcoder 肯定是正确的,Q - n%q
是不正确的。它应该是 n%Q
。此外,计算 size = (3*n)/4
也不可靠;在给定 vector [1, 2, 3, 4, 5, 0]
。
您可以通过简单地检查每个数组下标赋值时的索引值来避免让很多人盯着您的代码(尽管那样不会捕捉到 qsort
中的赋值,但更多内容见下文)。
您肯定已经想到您正在使用大量内存来执行一个简单的操作,而这实际上可以就地完成。通常避免进行就地操作的原因是您需要保留原始 vector ,但您使用 qsort
计算中位数,它就地排序,因此原始 vector 已经被修改.如果这是可以接受的,那么就没有理由不就地执行其余的中位数算法。 [1]
顺便说一句,虽然我肯定不是那些害怕浮点计算的人之一,但完全没有理由 countSets = ceil(float(n)/float(Q))
。 (n + Q - 1)/Q
就可以了。该成语也可以有用地用于计算 size
,尽管我完全不确定您首先从哪里获得 3n/4
计算.
[注1] 提示:不要连续分组,而是将 vector 分成五个区域,求每个区域第i个元素的中值。找到它后,将它与第一个区域的第 ith 元素交换;完成后,您的第一个区域—— vector 的前五分之一——包含中位数,您可以在该子 vector 上递归。这意味着实际上将中值代码写成一系列比较,这很乏味,但比调用 qsort
快得多。这也避免了我上面提到的退化情况,其中中位数计算错误地返回 vector 中的最小元素。
关于c++ - 在递归函数中释放内存时堆损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13430189/