我正在研究一个对矢量进行操作的简单库。 它定义了一种经常使用的函数类型:
typedef float (*vec_pair_fun) (float x, float y);
为了易于使用的原因,我想创建一个使用vec_pair_fun
来比较向量的每个元素的排序函数。
目前,我正在这样做:
static vec_pair_fun sort_function;
// follow improvements suggested by @chux below
static int converted_sort_function(const void* a, const void* b){
//old code: return (int) qsort_function(*(float*)a,*(float*)b);
float f = sort_function(*(float*)a,*(float*)b);
return (f > 0.0f) - (f < 0.0f);
}
void vecx_sort(int x, float v[], vec_pair_fun func){
sort_function=func;
qsort(v,x,sizeof(float),converted_sort_function);
}
但我并不喜欢这种解决方法,因为它不是线程安全的,因为sort_function
可以被另一个线程更改。
有关如何改善这一点的想法吗?
编辑: 一种方法是自己对数组进行排序。 重新编码qsort真的不是我打算做的,所以我真的愿意接受建议
答案 0 :(得分:1)
float
结果投射到int
进行比较。
也许不是OP的主要关注点,但(int) sort_function(*(float*)a,*(float*)b);
很弱
FP点结果可以是-0.4
或0.4
,这两者都会转换为(int) 0
。
FP点结果可以是> INT_MAX
,转换为int
是UB
建议:
static int converted_sort_function(const void* a, const void* b){
float f = sort_function(*(float*)a,*(float*)b);
return (f > 0.0f) - (f < 0.0f);
}
关于线程安全问题,请考虑传递上下文指针的qsort_s()
。 qsort_s()
在C11附录K中指定,因此它可能不存在于您的编译器中。
errno_t qsort_s(void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context);
答案 1 :(得分:0)
在快速排序算法的wikibooks 5th C implementation和Apple's implementation之后,我能够创建我的函数。 它似乎比stdlib版本更快,并且它没有全局/静态变量。
// x: length of v
// v: array of float
// func: a function that takes two float as argument and return a float
void vecx_qsort(unsigned int x, float v[], vec_pair_fun cmpf)
{
float pivot,tmp;
unsigned int al,l,r,ar,cnt;
while (x>8)
{
cnt=0;
al=l=1; r=ar=x-1;
pivot=v[x/2];
v[x/2]=v[0];
v[0]=pivot;
while (1)
{
while ( l<=r && (tmp=cmpf(v[l],pivot))<=0.0f ) {
if(tmp==0.0f){
cnt=1;
vecx_swap(1,v+al,v+l); //swap vl & val
al++;
}
l++;
}
while ( l<=r && (tmp=cmpf(v[r],pivot))>=0.0f ) {
if(tmp==0.0f){
cnt=1;
vecx_swap(1,v+r,v+ar);//swap vr & var
ar--;
}
r--;
}
if(l>r)
break;
cnt=1;
vecx_swap(1,v+r,v+l);
l++; r--;
}
if(cnt==0 && x<=32) // no swap made => almost sorted small array => insertion sort
break;
// swap values equal to pivot to the center
cnt = (al<(l-al))?al:l-al;
vecx_swap(cnt,v,v+l-cnt); // swap of element before al
cnt = ((ar-r)<(x-ar-1))?ar-r:x-ar-1;
vecx_swap(cnt,v+l,v+x-cnt); // swap of element after ar
l=l-al; // size of "smaller element array"
r=ar-r; // size of "bigger element array"
// Recursion on the shorter side & loop (with new indexes) on the longer
if (l>r) {
vecx_qsort(r, v+x-r, cmpf);
x=l;
}
else {
vecx_qsort(l, v, cmpf);
v+=x-r;
x=r;
}
}
// insertion sort
for (r=1; r<x; r++)
{
pivot=v[r];
for(l=r; l>0 && cmpf(pivot,v[l-1])<0.0f; l--)
v[l]=v[l-1];
v[l]=pivot;
}
}