xref: /csrg-svn/lib/libc/stdlib/qsort.c (revision 57588)
157056Selan /*
257056Selan  * Copyright (c) 1992 The Regents of the University of California.
334434Sbostic  * All rights reserved.
434434Sbostic  *
557056Selan  *
642126Sbostic  * %sccs.include.redist.c%
722102Smckusick  */
81975Swnj 
922102Smckusick 
1057056Selan #ifndef lint
1157056Selan static char copyright[] =
1257056Selan "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
1357056Selan  All rights reserved.\n";
1457056Selan #endif /* not lint */
1557056Selan 
1657056Selan #ifndef lint
17*57588Selan static char sccsid[] = "@(#)qsort.c	5.13 (Berkeley) 01/18/93";
1857056Selan #endif /* not lint */
1957056Selan 
2045643Sbostic #include <sys/types.h>
2142179Sbostic 
2257056Selan static char	*med3 __P((char *, char *, char *, int (*)()));
2357056Selan static void	 swapfunc __P((char *, char *, int, int));
2454201Sbostic 
2557056Selan #define min(a, b) (a) < (b) ? a : b
261975Swnj 
2745643Sbostic /*
2857056Selan  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
2945643Sbostic  */
3057056Selan #define swapcode(TYPE, parmi, parmj, n) { 		\
3157056Selan 	long i = (n) / sizeof (TYPE); 			\
3257056Selan 	register TYPE *pi = (TYPE *) (parmi); 		\
3357056Selan 	register TYPE *pj = (TYPE *) (parmj); 		\
3457056Selan 	do { 						\
3557056Selan 		register TYPE	t = *pi;		\
3657056Selan 		*pi++ = *pj;				\
3757056Selan 		*pj++ = t;				\
3857056Selan         } while (--i > 0);				\
3957056Selan }
401975Swnj 
4157056Selan #define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
4257056Selan 	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
4357056Selan 
4457056Selan static void
4557056Selan swapfunc(a, b, n, swaptype)
4657056Selan 	char *a, *b;
4757056Selan 	int n, swaptype;
4845643Sbostic {
4957056Selan 	if(swaptype <= 1)
5057056Selan 		swapcode(long, a, b, n)
5145643Sbostic 	else
5257056Selan 		swapcode(char, a, b, n)
5345643Sbostic }
5445643Sbostic 
5557056Selan #define swap(a, b) \
5657056Selan 	if (swaptype == 0) { \
5757056Selan 		long t = *(long *)(a); \
5857056Selan 		*(long *)(a) = *(long *)(b); \
5957056Selan 		*(long *)(b) = t; \
6057056Selan 	} else \
6157056Selan 		swapfunc(a, b, es, swaptype)
621975Swnj 
6357056Selan #define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
6457056Selan 
6557056Selan static char *
6657056Selan med3(a, b, c, cmp)
6757056Selan 	char *a, *b, *c;
6857056Selan 	int (*cmp)();
6957056Selan {
7057056Selan 	return cmp(a, b) < 0 ?
7157056Selan 	       (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
7257056Selan               :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
7345643Sbostic }
7445643Sbostic 
7557056Selan void
7657056Selan qsort(a, n, es, cmp)
7757056Selan 	void *a;
7857056Selan 	size_t n, es;
7957056Selan 	int (*cmp)();
8011449Smckusick {
8157056Selan 	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
8257056Selan 	int d, r, swaptype, swap_cnt;
831975Swnj 
8457056Selan loop:	SWAPINIT(a, es);
8557056Selan 	swap_cnt = 0;
8657056Selan 	if (n < 7) {
8757056Selan 		for (pm = a + es; pm < (char *) a + n * es; pm += es)
8857056Selan 			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
8957056Selan 			     pl -= es)
9057056Selan 				swap(pl, pl - es);
9157056Selan 		return;
9257056Selan 	}
9357056Selan 	pm = a + (n / 2) * es;
9457056Selan 	if (n > 7) {
9557056Selan 		pl = a;
9657056Selan 		pn = a + (n - 1) * es;
9757056Selan 		if (n > 40) {
9857056Selan 			d = (n / 8) * es;
9957056Selan 			pl = med3(pl, pl + d, pl + 2 * d, cmp);
10057056Selan 			pm = med3(pm - d, pm, pm + d, cmp);
10157056Selan 			pn = med3(pn - 2 * d, pn - d, pn, cmp);
10211449Smckusick 		}
10357056Selan 		pm = med3(pl, pm, pn, cmp);
10411449Smckusick 	}
10557056Selan 	swap(a, pm);
10657056Selan 	pa = pb = a + es;
10745643Sbostic 
10857056Selan 	pc = pd = a + (n - 1) * es;
10957056Selan 	for (;;) {
11057056Selan 		while (pb <= pc && (r = cmp(pb, a)) <= 0) {
11157056Selan 			if (r == 0) {
11257056Selan 				swap_cnt = 1;
11357056Selan 				swap(pa, pb);
11457056Selan 				pa += es;
1151975Swnj 			}
11657056Selan 			pb += es;
11757056Selan 		}
11857056Selan 		while (pb <= pc && (r = cmp(pc, a)) >= 0) {
11957056Selan 			if (r == 0) {
12057056Selan 				swap_cnt = 1;
12157056Selan 				swap(pc, pd);
12257056Selan 				pd -= es;
12345643Sbostic 			}
12457056Selan 			pc -= es;
1251975Swnj 		}
12657056Selan 		if (pb > pc)
12745643Sbostic 			break;
12857056Selan 		swap(pb, pc);
12957056Selan 		swap_cnt = 1;
13057056Selan 		pb += es;
13157056Selan 		pc -= es;
13211449Smckusick 	}
13357056Selan 	if (swap_cnt == 0) {  /* Switch to insertion sort */
13457056Selan 		for (pm = a + es; pm < (char *) a + n * es; pm += es)
13557056Selan 			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
13657056Selan 			     pl -= es)
13757056Selan 				swap(pl, pl - es);
13845643Sbostic 		return;
13945643Sbostic 	}
14011449Smckusick 
14157056Selan 	pn = a + n * es;
14257056Selan 	r = min(pa - (char *)a, pb - pa);
14357056Selan 	vecswap(a, pb - r, r);
14457056Selan 	r = min(pd - pc, pn - pd - es);
14557056Selan 	vecswap(pb, pn - r, r);
146*57588Selan 	if ((r = pb - pa) > es)
147*57588Selan 		qsort(a, r / es, es, cmp);
148*57588Selan 	if ((r = pd - pc) > es) {
149*57588Selan 		/* Iterate rather than recurse to save stack space */
150*57588Selan 		a = pn - r;
15157056Selan 		n = r / es;
15257056Selan 		goto loop;
15345643Sbostic 	}
154*57588Selan /*		qsort(pn - r, r / es, es, cmp);*/
1551975Swnj }
15657056Selan 
157