简体   繁体   中英

convert function for use with qsort

I'm working on a simple library which operate on vectors. It define a type of function that is regularly used:

typedef float (*vec_pair_fun) (float x, float y);

For ease-of-use reason, I want to create a sorting function that use a vec_pair_fun to compare each element of a vector. At the moment, I'm doing this:

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);
}

but I don't really like that workaround because it's not threadsafe as sort_function can be changed by another thread.

Any idea on how to improve this?


EDIT: One way would be to sort the array myself. Recoding qsort is really not what I planned to do, so I'm really open for suggestions

Q: Any idea on how to improve this?
A: Do not cast float result to int for compare.

Maybe not OP's main concern but (int) sort_function(*(float*)a,*(float*)b); is weak.
The FP point result could be -0.4 or 0.4 , both of these convert to (int) 0 .
The FP point result could be > INT_MAX and conversion to int is UB.
Suggest:

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);
}

As to your thread safe problem, consider qsort_s() which passes in a context pointer. qsort_s() is specified in C11 Annex K, so it may not exist in your compiler.

errno_t qsort_s(void *base, rsize_t nmemb, rsize_t size,
    int (*compar)(const void *x, const void *y, void *context), 
    void *context);

Following wikibooks 5th C implementation and Apple's implementation of a quicksort algorithm, I was able to create my function. It appear to be quicker than the stdlib version, and it has no global/static variable.

// 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;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM