shithub: scc

ref: 428e86f306625a3192e03260a921a19c3109f57d
dir: /lib/c/src/qsort.c/

View raw version

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