我正在实现一种算法来选择数组的第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;
}
答案 0 :(得分:1)
@Dcoder肯定是Q - n%q
不正确的。它应该是n%Q
。另外,计算size = (3*n)/4
不可靠;在给定向量n = 6
的情况下,尝试Q
(假设,似乎确定[1, 2, 3, 4, 5, 0]
实际上是5)。
你可以通过简单地检查每个数组下标赋值的索引值来避免让很多人看着你的代码(尽管那不会捕获qsort
内部的赋值,但更多的是以下)。
你肯定已经想到你正在使用大量的内存来执行简单的操作,这实际上可以就地完成。通常,避免执行就地操作的原因是您需要保留原始向量,但是您正在计算具有qsort
的中位数,其中就地排序,因此原始向量已经被修改。如果这是可以接受的,那么就没有理由不在其他地方使用中位数算法。 [1]
顺便说一下,虽然我当然不是那些害怕浮点计算的人之一,但{I}毫无理由。countSets = ceil(float(n)/float(Q))
。 (n + Q - 1)/Q
可以正常使用。这个习惯用法也可以用来计算size
,虽然我完全不确定你从哪里得到3n/4
计算。
[注1]提示:不是连续分组,而是将矢量分成五个区域,找到每个区域的i th 元素的中值。一旦找到它,将其与第一个区域的i th 元素交换;一旦完成,你的第一个区域 - 向量的前五分之一 - 包含中位数,你可以在该子向量上递归。这意味着实际上将中间代码写为一系列比较,这比调用qsort
要繁琐但速度快得多。这也避免了我上面提到的退化情况,其中中位数计算错误地返回了向量中的最小元素。