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