转换函数用于qsort

时间:2014-11-22 20:10:31

标签: c

我正在研究一个对矢量进行操作的简单库。 它定义了一种经常使用的函数类型:

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真的不是我打算做的,所以我真的愿意接受建议

2 个答案:

答案 0 :(得分:1)

问:关于如何改进这个问题的任何想法?
答:不要将float结果投射到int进行比较。

也许不是OP的主要关注点,但(int) sort_function(*(float*)a,*(float*)b);很弱 FP点结果可以是-0.40.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 implementationApple'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;
    }
}