快速排序qsort()源码及使用实例。

来源:互联网 发布:手机淘宝彩票在哪里 编辑:程序博客网 时间:2024/05/19 12:29
qsort()是最有效的快排序法之一。其函数原型是viod qsort(void *base, size_t_nmemb, size_t_size, int (*compar)( const void *), const void *);第一个参数为指向要排序的数组头部的指针。第二个参数为需要排序的项目数量。因为qsort()将第一个参数转换为void指针,所以会失去每个数组元素大小的信息,为了补充该信息,需要将数组大小告诉qsort()。第三个参数是一个指向函数的指针,被指向的函数用于确定排序顺序。这个比较函数应该接受两个参数,即分别指向进行比较的两个项目的指针。以下是调用qsort()函数的函数实例。/*qsorter.c 使用qsort()对一组数字排序*/#include <stdio.h>#include <stdlib.h>#define NUM 40void fillarray (double ar[], int n);void showarray (const double ar[], int n);int mycopy(const void *p1, const void *p2);int main (void){double vals[NUM];fillarray(vals,NUM);puts("Random list:");showarray(vals, NUM);qsort(vals,NUM,sizeof (double),mycopy);puts("\nSorted list:");showarray(vals,NUM);return 0;}void fillarray (double ar[], int n){int index;for (index = 0; index < n; index ++){ar[index] = (double)rand()/((double)rand()+0.1);}}void showarray (const double ar[], int n){int index;for (index = 0; index < n; index ++){printf ("%9.4f",ar[index])if (index & 6 == 5)putchar('\n');}if (index % 6 != 0)putchar('\n');}int mycopy (const void *p1, const void *p2){const double *a1 = (const double *) p1;const double *a2 = (const double *) p2;if (*a1 < *a2)return -1;else if (*a1 == *a2)return 0;elsereturn 1;}----------------------------------------------------------------以下是搜索到的qsort()函数源码---------------------------------------------------------<pre id="best-content-281179165" class="best-text mb-10">void __fileDECL qsort (    void *base,    size_t num,    size_t width,    int (__fileDECL *comp)(const void *, const void *)    )#endif  /* __USE_CONTEXT */{    char *lo, *hi;              /* ends of sub-array currently sorting */    char *mid;                  /* points to middle of subarray */    char *loguy, *higuy;        /* traveling pointers for partition step */    size_t size;                /* size of the sub-array */    char *lostk[STKSIZ], *histk[STKSIZ];    int stkptr;                 /* stack for saving sub-array to be processed */    /* validation section */    _VALIDATE_RETURN_VOID(base != NULL || num == 0, EINVAL);    _VALIDATE_RETURN_VOID(width > 0, EINVAL);    _VALIDATE_RETURN_VOID(comp != NULL, EINVAL);    if (num < 2)        return;                 /* nothing to do */    stkptr = 0;                 /* initialize stack */    lo = (char *)base;    hi = (char *)base + width * (num-1);        /* initialize limits */    /* this entry point is for pseudo-recursion calling: setting       lo and hi and jumping to here is like recursion, but stkptr is       preserved, locals aren't, so we preserve stuff on the stack */recurse:    size = (hi - lo) / width + 1;        /* number of el's to sort */    /* below a certain size, it is faster to use a O(n^2) sorting method */    if (size <= CUTOFF) {        __SHORTSORT(lo, hi, width, comp, context);    }    else {        /* First we pick a partitioning element.  The efficiency of the           algorithm demands that we find one that is approximately the median           of the values, but also that we select one fast.  We choose the           median of the first, middle, and last elements, to avoid bad           performance in the face of already sorted data, or data that is made           up of multiple sorted runs appended together.  Testing shows that a           median-of-three algorithm provides better performance than simply           picking the middle element for the latter case. */        mid = lo + (size / 2) * width;      /* find middle element */        /* Sort the first, middle, last elements into order */        if (__COMPARE(context, lo, mid) > 0) {            swap(lo, mid, width);        }        if (__COMPARE(context, lo, hi) > 0) {            swap(lo, hi, width);        }        if (__COMPARE(context, mid, hi) > 0) {            swap(mid, hi, width);        }        /* We now wish to partition the array into three pieces, one consisting           of elements <= partition element, one of elements equal to the           partition element, and one of elements > than it.  This is done           below; comments indicate conditions established at every step. */        loguy = lo;        higuy = hi;        /* Note that higuy decreases and loguy increases on every iteration,           so loop must terminate. */        for (;;) {            /* lo <= loguy < hi, lo < higuy <= hi,               A[i] <= A[mid] for lo <= i <= loguy,               A[i] > A[mid] for higuy <= i < hi,               A[hi] >= A[mid] */            /* The doubled loop is to avoid calling comp(mid,mid), since some               existing comparison funcs don't work when passed the same               value for both pointers. */            if (mid > loguy) {                do  {                    loguy += width;                } while (loguy < mid && __COMPARE(context, loguy, mid) <= 0);            }            if (mid <= loguy) {                do  {                    loguy += width;                } while (loguy <= hi && __COMPARE(context, loguy, mid) <= 0);            }            /* lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy,               either loguy > hi or A[loguy] > A[mid] */            do  {                higuy -= width;            } while (higuy > mid && __COMPARE(context, higuy, mid) > 0);            /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi,               either higuy == lo or A[higuy] <= A[mid] */            if (higuy < loguy)                break;            /* if loguy > hi or higuy == lo, then we would have exited, so               A[loguy] > A[mid], A[higuy] <= A[mid],               loguy <= hi, higuy > lo */            swap(loguy, higuy, width);            /* If the partition element was moved, follow it.  Only need               to check for mid == higuy, since before the swap,               A[loguy] > A[mid] implies loguy != mid. */            if (mid == higuy)                mid = loguy;            /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top               of loop is re-established */        }        /*     A[i] <= A[mid] for lo <= i < loguy,               A[i] > A[mid] for higuy < i < hi,               A[hi] >= A[mid]               higuy < loguy           implying:               higuy == loguy-1               or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] */        /* Find adjacent elements equal to the partition element.  The           doubled loop is to avoid calling comp(mid,mid), since some           existing comparison funcs don't work when passed the same value           for both pointers. */        higuy += width;        if (mid < higuy) {            do  {                higuy -= width;            } while (higuy > mid && __COMPARE(context, higuy, mid) == 0);        }        if (mid >= higuy) {            do  {                higuy -= width;            } while (higuy > lo && __COMPARE(context, higuy, mid) == 0);        }        /* OK, now we have the following:              higuy < loguy              lo <= higuy <= hi              A[i]  <= A[mid] for lo <= i <= higuy              A[i]  == A[mid] for higuy < i < loguy              A[i]  >  A[mid] for loguy <= i < hi              A[hi] >= A[mid] */        /* We've finished the partition, now we want to sort the subarrays           [lo, higuy] and [loguy, hi].           We do the smaller one first to minimize stack usage.           We only sort arrays of length 2 or more.*/        if ( higuy - lo >= hi - loguy ) {            if (lo < higuy) {                lostk[stkptr] = lo;                histk[stkptr] = higuy;                ++stkptr;            }                           /* save big recursion for later */            if (loguy < hi) {                lo = loguy;                goto recurse;           /* do small recursion */            }        }        else {            if (loguy < hi) {                lostk[stkptr] = loguy;                histk[stkptr] = hi;                ++stkptr;               /* save big recursion for later */            }            if (lo < higuy) {                hi = higuy;                goto recurse;           /* do small recursion */            }        }    }    /* We have sorted the array, except for any pending sorts on the stack.       Check if there are any, and do them. */    --stkptr;    if (stkptr >= 0) {        lo = lostk[stkptr];        hi = histk[stkptr];        goto recurse;           /* pop subarray from stack */    }    else        return;                 /* all subarrays done */}


0 0
原创粉丝点击