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