xref: /plan9/sys/src/libc/port/qsort.c (revision e8ece30e958f586a4dcfe69d224c5cce2445b17b)
1bd389b36SDavid du Colombier /*
2219b2ee8SDavid du Colombier  * qsort -- simple quicksort
3bd389b36SDavid du Colombier  */
43e12c5d1SDavid du Colombier 
5*e8ece30eSDavid du Colombier #include <u.h>
6*e8ece30eSDavid du Colombier 
7219b2ee8SDavid du Colombier typedef
8219b2ee8SDavid du Colombier struct
93e12c5d1SDavid du Colombier {
10219b2ee8SDavid du Colombier 	int	(*cmp)(void*, void*);
11219b2ee8SDavid du Colombier 	void	(*swap)(char*, char*, long);
12219b2ee8SDavid du Colombier 	long	es;
13219b2ee8SDavid du Colombier } Sort;
143e12c5d1SDavid du Colombier 
15219b2ee8SDavid du Colombier static	void
swapb(char * i,char * j,long es)16219b2ee8SDavid du Colombier swapb(char *i, char *j, long es)
17bd389b36SDavid du Colombier {
18219b2ee8SDavid du Colombier 	char c;
193e12c5d1SDavid du Colombier 
20219b2ee8SDavid du Colombier 	do {
21219b2ee8SDavid du Colombier 		c = *i;
22219b2ee8SDavid du Colombier 		*i++ = *j;
23219b2ee8SDavid du Colombier 		*j++ = c;
24219b2ee8SDavid du Colombier 		es--;
25219b2ee8SDavid du Colombier 	} while(es != 0);
26219b2ee8SDavid du Colombier 
27bd389b36SDavid du Colombier }
28219b2ee8SDavid du Colombier 
29219b2ee8SDavid du Colombier static	void
swapi(char * ii,char * ij,long es)30219b2ee8SDavid du Colombier swapi(char *ii, char *ij, long es)
31219b2ee8SDavid du Colombier {
32219b2ee8SDavid du Colombier 	long *i, *j, c;
33219b2ee8SDavid du Colombier 
34219b2ee8SDavid du Colombier 	i = (long*)ii;
35219b2ee8SDavid du Colombier 	j = (long*)ij;
36219b2ee8SDavid du Colombier 	do {
37219b2ee8SDavid du Colombier 		c = *i;
38219b2ee8SDavid du Colombier 		*i++ = *j;
39219b2ee8SDavid du Colombier 		*j++ = c;
40219b2ee8SDavid du Colombier 		es -= sizeof(long);
41219b2ee8SDavid du Colombier 	} while(es != 0);
42bd389b36SDavid du Colombier }
43219b2ee8SDavid du Colombier 
44219b2ee8SDavid du Colombier static	char*
pivot(char * a,long n,Sort * p)45219b2ee8SDavid du Colombier pivot(char *a, long n, Sort *p)
46219b2ee8SDavid du Colombier {
47219b2ee8SDavid du Colombier 	long j;
48219b2ee8SDavid du Colombier 	char *pi, *pj, *pk;
49219b2ee8SDavid du Colombier 
50219b2ee8SDavid du Colombier 	j = n/6 * p->es;
51219b2ee8SDavid du Colombier 	pi = a + j;	/* 1/6 */
52219b2ee8SDavid du Colombier 	j += j;
53219b2ee8SDavid du Colombier 	pj = pi + j;	/* 1/2 */
54219b2ee8SDavid du Colombier 	pk = pj + j;	/* 5/6 */
55219b2ee8SDavid du Colombier 	if(p->cmp(pi, pj) < 0) {
56219b2ee8SDavid du Colombier 		if(p->cmp(pi, pk) < 0) {
57219b2ee8SDavid du Colombier 			if(p->cmp(pj, pk) < 0)
58219b2ee8SDavid du Colombier 				return pj;
59219b2ee8SDavid du Colombier 			return pk;
60bd389b36SDavid du Colombier 		}
61219b2ee8SDavid du Colombier 		return pi;
62219b2ee8SDavid du Colombier 	}
63219b2ee8SDavid du Colombier 	if(p->cmp(pj, pk) < 0) {
64219b2ee8SDavid du Colombier 		if(p->cmp(pi, pk) < 0)
65219b2ee8SDavid du Colombier 			return pi;
66219b2ee8SDavid du Colombier 		return pk;
67219b2ee8SDavid du Colombier 	}
68219b2ee8SDavid du Colombier 	return pj;
69219b2ee8SDavid du Colombier }
70219b2ee8SDavid du Colombier 
71219b2ee8SDavid du Colombier static	void
qsorts(char * a,long n,Sort * p)72219b2ee8SDavid du Colombier qsorts(char *a, long n, Sort *p)
73219b2ee8SDavid du Colombier {
74219b2ee8SDavid du Colombier 	long j, es;
75219b2ee8SDavid du Colombier 	char *pi, *pj, *pn;
76219b2ee8SDavid du Colombier 
77219b2ee8SDavid du Colombier 	es = p->es;
78219b2ee8SDavid du Colombier 	while(n > 1) {
79219b2ee8SDavid du Colombier 		if(n > 10) {
80219b2ee8SDavid du Colombier 			pi = pivot(a, n, p);
81219b2ee8SDavid du Colombier 		} else
82219b2ee8SDavid du Colombier 			pi = a + (n>>1)*es;
83219b2ee8SDavid du Colombier 
84219b2ee8SDavid du Colombier 		p->swap(a, pi, es);
85219b2ee8SDavid du Colombier 		pi = a;
86219b2ee8SDavid du Colombier 		pn = a + n*es;
87219b2ee8SDavid du Colombier 		pj = pn;
883e12c5d1SDavid du Colombier 		for(;;) {
89219b2ee8SDavid du Colombier 			do
90219b2ee8SDavid du Colombier 				pi += es;
91219b2ee8SDavid du Colombier 			while(pi < pn && p->cmp(pi, a) < 0);
92219b2ee8SDavid du Colombier 			do
93219b2ee8SDavid du Colombier 				pj -= es;
94219b2ee8SDavid du Colombier 			while(pj > a && p->cmp(pj, a) > 0);
95219b2ee8SDavid du Colombier 			if(pj < pi)
96bd389b36SDavid du Colombier 				break;
97219b2ee8SDavid du Colombier 			p->swap(pi, pj, es);
983e12c5d1SDavid du Colombier 		}
99219b2ee8SDavid du Colombier 		p->swap(a, pj, es);
100219b2ee8SDavid du Colombier 		j = (pj - a) / es;
101219b2ee8SDavid du Colombier 
102219b2ee8SDavid du Colombier 		n = n-j-1;
103219b2ee8SDavid du Colombier 		if(j >= n) {
104219b2ee8SDavid du Colombier 			qsorts(a, j, p);
105219b2ee8SDavid du Colombier 			a += (j+1)*es;
1063e12c5d1SDavid du Colombier 		} else {
107219b2ee8SDavid du Colombier 			qsorts(a + (j+1)*es, n, p);
108219b2ee8SDavid du Colombier 			n = j;
1093e12c5d1SDavid du Colombier 		}
1103e12c5d1SDavid du Colombier 	}
1113e12c5d1SDavid du Colombier }
1123e12c5d1SDavid du Colombier 
1133e12c5d1SDavid du Colombier void
qsort(void * va,long n,long es,int (* cmp)(void *,void *))114219b2ee8SDavid du Colombier qsort(void *va, long n, long es, int (*cmp)(void*, void*))
1153e12c5d1SDavid du Colombier {
116219b2ee8SDavid du Colombier 	Sort s;
1173e12c5d1SDavid du Colombier 
118219b2ee8SDavid du Colombier 	s.cmp = cmp;
119219b2ee8SDavid du Colombier 	s.es = es;
120219b2ee8SDavid du Colombier 	s.swap = swapi;
121*e8ece30eSDavid du Colombier 	if(((uintptr)va | es) % sizeof(long))
122219b2ee8SDavid du Colombier 		s.swap = swapb;
123219b2ee8SDavid du Colombier 	qsorts((char*)va, n, &s);
1243e12c5d1SDavid du Colombier }
125