ref: 428e86f306625a3192e03260a921a19c3109f57d
dir: /lib/c/src/qsort.c/
#include <stdlib.h> #include <string.h> #undef qsort /* * This implementation of qsort is based in the paper * "Engineering a Sort Function", by Jon L.Bentley and M. Douglas McIlroy */ struct qsort { size_t es; int (*cmp)(const void *, const void *); void (*swap)(char *i, char *j, size_t n); }; static void swapb(char *i, char *j, size_t n) { do { char c = *i; *i++ = *j; *j++ = c; } while (--n > 0); } static void swapw(char *i, char *j, size_t n) { int w, *wi = (int *) i, *wj = (int *) j; n /= sizeof(w); do { w = *wi; *wi++ = *wj; *wj++ = w; } while (--n > 0); } static void swapl(char *i, char *j, size_t n) { char *tmp[n]; memcpy(tmp, i, n); memcpy(i, j, n); memcpy(j, tmp, n); } static char * med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) { if (cmp(a, b) < 0) { if (cmp(b, c) < 0) return b; return (cmp(a, c) < 0) ? c : a; } else { if (cmp(b, c) > 0) return b; return (cmp(a, c) > 0) ? c : a; } } static char * pivot(char *v, size_t n, struct qsort *qs) { char *p1, *pm, *pn; /* 1st, middle, nth */ int (*cmp)(const void *, const void *); size_t s, es = qs->es; pm = v + n/2 * es; if (n < 10) return pm; cmp = qs->cmp; s = n/6 * es; p1 = v + s; pn = pm + 2*s; if (n > 50) { s = n/8 * es; p1 = med3(p1, p1+s, p1 + 2*s, cmp); pm = med3(pm-s, pm, pm+s, cmp); pn = med3(pn-2*s, pn-s, pn, cmp); } return med3(p1, pm, pn, qs->cmp); } static void xqsort(char *a, size_t n, struct qsort *qs) { size_t j, es = qs->es; char *pi, *pj, *pn; tail_recursion: if (n <= 1) return; pi = a; pn = pj = a + n*es; qs->swap(a, pivot(a, n, qs), es); for (;;) { do { pi += es; } while (pi < pn && qs->cmp(pi, pn) < 0); do { pj -= es; } while (pj > a && qs->cmp(pj, a) > 0); if (pj < pi) break; qs->swap(pi, pj, es); } qs->swap(a, pj, es); /* * We have to recurse over two subarrays. One of them can be * optimized with tail recursion. We select to recurse over * the bigger subarray, because it will allow us to apply a * better divide and conquer strategy. */ j = (pj - a) / es; if (j >= n) { xqsort(a, j, qs); a += (j+1) * es; } else { xqsort(a + (j+1) * es, n-j-1, qs); n = j; } goto tail_recursion; } void qsort(void *base, size_t nmemb, size_t size, int (*f)(const void *, const void *)) { struct qsort qs; qs.cmp = f; qs.es = size; if (size > 7 * sizeof(int)) qs.swap = swapl; else if (size % sizeof(int) == 0) qs.swap = swapw; else qs.swap = swapb; xqsort(base, nmemb, &qs); }