|
|
1.1 root 1: /*-
2: * Copyright (c) 1980, 1983 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #if defined(LIBC_SCCS) && !defined(lint)
21: static char sccsid[] = "@(#)qsort.c 5.7 (Berkeley) 5/17/90";
22: #endif /* LIBC_SCCS and not lint */
23:
24: #include <stdlib.h>
25:
26: /*
27: * qsort.c:
28: * Our own version of the system qsort routine which is faster by an average
29: * of 25%, with lows and highs of 10% and 50%.
30: * The THRESHold below is the insertion sort threshold, and has been adjusted
31: * for records of size 48 bytes.
32: * The MTHREShold is where we stop finding a better median.
33: */
34:
35: #define THRESH 4 /* threshold for insertion */
36: #define MTHRESH 6 /* threshold for median */
37:
38: static int (*qcmp)(); /* the comparison routine */
39: static int qsz; /* size of each record */
40: static int thresh; /* THRESHold in chars */
41: static int mthresh; /* MTHRESHold in chars */
42:
43: /*
44: * qsort:
45: * First, set up some global parameters for qst to share. Then, quicksort
46: * with qst(), and then a cleanup insertion sort ourselves. Sound simple?
47: * It's not...
48: */
49:
50: void
51: qsort(base, n, size, compar)
52: char *base;
53: int n;
54: int size;
55: int (*compar)();
56: {
57: register char c, *i, *j, *lo, *hi;
58: char *min, *max;
59:
60: if (n <= 1)
61: return;
62: qsz = size;
63: qcmp = compar;
64: thresh = qsz * THRESH;
65: mthresh = qsz * MTHRESH;
66: max = base + n * qsz;
67: if (n >= THRESH) {
68: qst(base, max);
69: hi = base + thresh;
70: } else {
71: hi = max;
72: }
73: /*
74: * First put smallest element, which must be in the first THRESH, in
75: * the first position as a sentinel. This is done just by searching
76: * the first THRESH elements (or the first n if n < THRESH), finding
77: * the min, and swapping it into the first position.
78: */
79: for (j = lo = base; (lo += qsz) < hi; )
80: if (qcmp(j, lo) > 0)
81: j = lo;
82: if (j != base) {
83: /* swap j into place */
84: for (i = base, hi = base + qsz; i < hi; ) {
85: c = *j;
86: *j++ = *i;
87: *i++ = c;
88: }
89: }
90: /*
91: * With our sentinel in place, we now run the following hyper-fast
92: * insertion sort. For each remaining element, min, from [1] to [n-1],
93: * set hi to the index of the element AFTER which this one goes.
94: * Then, do the standard insertion sort shift on a character at a time
95: * basis for each element in the frob.
96: */
97: for (min = base; (hi = min += qsz) < max; ) {
98: while (qcmp(hi -= qsz, min) > 0)
99: /* void */;
100: if ((hi += qsz) != min) {
101: for (lo = min + qsz; --lo >= min; ) {
102: c = *lo;
103: for (i = j = lo; (j -= qsz) >= hi; i = j)
104: *i = *j;
105: *i = c;
106: }
107: }
108: }
109: }
110:
111: /*
112: * qst:
113: * Do a quicksort
114: * First, find the median element, and put that one in the first place as the
115: * discriminator. (This "median" is just the median of the first, last and
116: * middle elements). (Using this median instead of the first element is a big
117: * win). Then, the usual partitioning/swapping, followed by moving the
118: * discriminator into the right place. Then, figure out the sizes of the two
119: * partions, do the smaller one recursively and the larger one via a repeat of
120: * this code. Stopping when there are less than THRESH elements in a partition
121: * and cleaning up with an insertion sort (in our caller) is a huge win.
122: * All data swaps are done in-line, which is space-losing but time-saving.
123: * (And there are only three places where this is done).
124: */
125:
126: static
127: qst(base, max)
128: char *base, *max;
129: {
130: register char c, *i, *j, *jj;
131: register int ii;
132: char *mid, *tmp;
133: int lo, hi;
134:
135: /*
136: * At the top here, lo is the number of characters of elements in the
137: * current partition. (Which should be max - base).
138: * Find the median of the first, last, and middle element and make
139: * that the middle element. Set j to largest of first and middle.
140: * If max is larger than that guy, then it's that guy, else compare
141: * max with loser of first and take larger. Things are set up to
142: * prefer the middle, then the first in case of ties.
143: */
144: lo = max - base; /* number of elements as chars */
145: do {
146: mid = i = base + qsz * ((lo / qsz) >> 1);
147: if (lo >= mthresh) {
148: j = (qcmp((jj = base), i) > 0 ? jj : i);
149: if (qcmp(j, (tmp = max - qsz)) > 0) {
150: /* switch to first loser */
151: j = (j == jj ? i : jj);
152: if (qcmp(j, tmp) < 0)
153: j = tmp;
154: }
155: if (j != i) {
156: ii = qsz;
157: do {
158: c = *i;
159: *i++ = *j;
160: *j++ = c;
161: } while (--ii);
162: }
163: }
164: /*
165: * Semi-standard quicksort partitioning/swapping
166: */
167: for (i = base, j = max - qsz; ; ) {
168: while (i < mid && qcmp(i, mid) <= 0)
169: i += qsz;
170: while (j > mid) {
171: if (qcmp(mid, j) <= 0) {
172: j -= qsz;
173: continue;
174: }
175: tmp = i + qsz; /* value of i after swap */
176: if (i == mid) {
177: /* j <-> mid, new mid is j */
178: mid = jj = j;
179: } else {
180: /* i <-> j */
181: jj = j;
182: j -= qsz;
183: }
184: goto swap;
185: }
186: if (i == mid) {
187: break;
188: } else {
189: /* i <-> mid, new mid is i */
190: jj = mid;
191: tmp = mid = i; /* value of i after swap */
192: j -= qsz;
193: }
194: swap:
195: ii = qsz;
196: do {
197: c = *i;
198: *i++ = *jj;
199: *jj++ = c;
200: } while (--ii);
201: i = tmp;
202: }
203: /*
204: * Look at sizes of the two partitions, do the smaller
205: * one first by recursion, then do the larger one by
206: * making sure lo is its size, base and max are update
207: * correctly, and branching back. But only repeat
208: * (recursively or by branching) if the partition is
209: * of at least size THRESH.
210: */
211: i = (j = mid) + qsz;
212: if ((lo = j - base) <= (hi = max - i)) {
213: if (lo >= thresh)
214: qst(base, j);
215: base = i;
216: lo = hi;
217: } else {
218: if (hi >= thresh)
219: qst(i, max);
220: max = j;
221: }
222: } while (lo >= thresh);
223: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.