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