[英]convert function for use with qsort
我正在研究一个对向量进行操作的简单库。 它定义了一种经常使用的函数类型:
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确实不是我计划要做的,所以我很愿意提出建议
问:关于如何改善这一点的想法?
答:请勿将float
结果int
为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()
。 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);
在Wikibooks的5th C实现和Apple的 quicksort算法实现之后,我得以创建函数。 它似乎比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;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.