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:     unsigned 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: }

Defined functions

qsort defined in line 35; used 70 times
qst defined in line 110; used 3 times

Defined variables

mthresh defined in line 26; used 2 times
qsz defined in line 24; used 23 times
sccsid defined in line 8; never used
thresh defined in line 25; used 5 times

Defined macros

MTHRESH defined in line 21; used 1 times
  • in line 49
THRESH defined in line 20; used 2 times
Last modified: 1990-07-25
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3121
Valid CSS Valid XHTML 1.0 Strict