xref: /csrg-svn/lib/libc/stdlib/qsort.c (revision 57056)
1*57056Selan /*
2*57056Selan  * Copyright (c) 1992 The Regents of the University of California.
334434Sbostic  * All rights reserved.
434434Sbostic  *
5*57056Selan  *
642126Sbostic  * %sccs.include.redist.c%
722102Smckusick  */
81975Swnj 
922102Smckusick 
10*57056Selan #ifndef lint
11*57056Selan static char copyright[] =
12*57056Selan "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
13*57056Selan  All rights reserved.\n";
14*57056Selan #endif /* not lint */
15*57056Selan 
16*57056Selan #ifndef lint
17*57056Selan static char sccsid[] = "@(#)qsort.c	5.11 (Berkeley) 12/10/92";
18*57056Selan #endif /* not lint */
19*57056Selan 
2045643Sbostic #include <sys/types.h>
2142179Sbostic 
22*57056Selan static char	*med3 __P((char *, char *, char *, int (*)()));
23*57056Selan static void	 swapfunc __P((char *, char *, int, int));
2454201Sbostic 
25*57056Selan #define min(a, b) (a) < (b) ? a : b
261975Swnj 
2745643Sbostic /*
28*57056Selan  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
2945643Sbostic  */
30*57056Selan #define swapcode(TYPE, parmi, parmj, n) { 		\
31*57056Selan 	long i = (n) / sizeof (TYPE); 			\
32*57056Selan 	register TYPE *pi = (TYPE *) (parmi); 		\
33*57056Selan 	register TYPE *pj = (TYPE *) (parmj); 		\
34*57056Selan 	do { 						\
35*57056Selan 		register TYPE	t = *pi;		\
36*57056Selan 		*pi++ = *pj;				\
37*57056Selan 		*pj++ = t;				\
38*57056Selan         } while (--i > 0);				\
39*57056Selan }
401975Swnj 
41*57056Selan #define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
42*57056Selan 	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
43*57056Selan 
44*57056Selan static void
45*57056Selan swapfunc(a, b, n, swaptype)
46*57056Selan 	char *a, *b;
47*57056Selan 	int n, swaptype;
4845643Sbostic {
49*57056Selan 	if(swaptype <= 1)
50*57056Selan 		swapcode(long, a, b, n)
5145643Sbostic 	else
52*57056Selan 		swapcode(char, a, b, n)
5345643Sbostic }
5445643Sbostic 
55*57056Selan #define swap(a, b) \
56*57056Selan 	if (swaptype == 0) { \
57*57056Selan 		long t = *(long *)(a); \
58*57056Selan 		*(long *)(a) = *(long *)(b); \
59*57056Selan 		*(long *)(b) = t; \
60*57056Selan 	} else \
61*57056Selan 		swapfunc(a, b, es, swaptype)
621975Swnj 
63*57056Selan #define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
64*57056Selan 
65*57056Selan static char *
66*57056Selan med3(a, b, c, cmp)
67*57056Selan 	char *a, *b, *c;
68*57056Selan 	int (*cmp)();
69*57056Selan {
70*57056Selan 	return cmp(a, b) < 0 ?
71*57056Selan 	       (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
72*57056Selan               :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
7345643Sbostic }
7445643Sbostic 
75*57056Selan void
76*57056Selan qsort(a, n, es, cmp)
77*57056Selan 	void *a;
78*57056Selan 	size_t n, es;
79*57056Selan 	int (*cmp)();
8011449Smckusick {
81*57056Selan 	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
82*57056Selan 	int d, r, swaptype, swap_cnt;
831975Swnj 
84*57056Selan loop:	SWAPINIT(a, es);
85*57056Selan 	swap_cnt = 0;
86*57056Selan 	if (n < 7) {
87*57056Selan 		for (pm = a + es; pm < (char *) a + n * es; pm += es)
88*57056Selan 			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
89*57056Selan 			     pl -= es)
90*57056Selan 				swap(pl, pl - es);
91*57056Selan 		return;
92*57056Selan 	}
93*57056Selan 	pm = a + (n / 2) * es;
94*57056Selan 	if (n > 7) {
95*57056Selan 		pl = a;
96*57056Selan 		pn = a + (n - 1) * es;
97*57056Selan 		if (n > 40) {
98*57056Selan 			d = (n / 8) * es;
99*57056Selan 			pl = med3(pl, pl + d, pl + 2 * d, cmp);
100*57056Selan 			pm = med3(pm - d, pm, pm + d, cmp);
101*57056Selan 			pn = med3(pn - 2 * d, pn - d, pn, cmp);
10211449Smckusick 		}
103*57056Selan 		pm = med3(pl, pm, pn, cmp);
10411449Smckusick 	}
105*57056Selan 	swap(a, pm);
106*57056Selan 	pa = pb = a + es;
10745643Sbostic 
108*57056Selan 	pc = pd = a + (n - 1) * es;
109*57056Selan 	for (;;) {
110*57056Selan 		while (pb <= pc && (r = cmp(pb, a)) <= 0) {
111*57056Selan 			if (r == 0) {
112*57056Selan 				swap_cnt = 1;
113*57056Selan 				swap(pa, pb);
114*57056Selan 				pa += es;
1151975Swnj 			}
116*57056Selan 			pb += es;
117*57056Selan 		}
118*57056Selan 		while (pb <= pc && (r = cmp(pc, a)) >= 0) {
119*57056Selan 			if (r == 0) {
120*57056Selan 				swap_cnt = 1;
121*57056Selan 				swap(pc, pd);
122*57056Selan 				pd -= es;
12345643Sbostic 			}
124*57056Selan 			pc -= es;
1251975Swnj 		}
126*57056Selan 		if (pb > pc)
12745643Sbostic 			break;
128*57056Selan 		swap(pb, pc);
129*57056Selan 		swap_cnt = 1;
130*57056Selan 		pb += es;
131*57056Selan 		pc -= es;
13211449Smckusick 	}
133*57056Selan 	if (swap_cnt == 0) {  /* Switch to insertion sort */
134*57056Selan 		for (pm = a + es; pm < (char *) a + n * es; pm += es)
135*57056Selan 			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
136*57056Selan 			     pl -= es)
137*57056Selan 				swap(pl, pl - es);
13845643Sbostic 		return;
13945643Sbostic 	}
14011449Smckusick 
141*57056Selan 	pn = a + n * es;
142*57056Selan 	r = min(pa - (char *)a, pb - pa);
143*57056Selan 	vecswap(a, pb - r, r);
144*57056Selan 	r = min(pd - pc, pn - pd - es);
145*57056Selan 	vecswap(pb, pn - r, r);
146*57056Selan 	if ((r = pb - pa) > es) {
147*57056Selan 		/*
148*57056Selan 		 * To decrease the stack space we iterate here rather than
149*57056Selan 		 * recurse.
150*57056Selan 		 */
151*57056Selan 		n = r / es;
152*57056Selan 		goto loop;
15345643Sbostic 	}
154*57056Selan 	if ((r = pd - pc) > es)
155*57056Selan 		nqsort(pn - r, r / es, es, cmp);
1561975Swnj }
157*57056Selan 
158