1*42126Sbostic /*- 2*42126Sbostic * Copyright (c) 1980, 1983 The Regents of the University of California. 334434Sbostic * All rights reserved. 434434Sbostic * 5*42126Sbostic * %sccs.include.redist.c% 622102Smckusick */ 71975Swnj 826577Sdonn #if defined(LIBC_SCCS) && !defined(lint) 9*42126Sbostic static char sccsid[] = "@(#)qsort.c 5.5 (Berkeley) 05/16/90"; 1034434Sbostic #endif /* LIBC_SCCS and not lint */ 1122102Smckusick 1211449Smckusick /* 1311449Smckusick * qsort.c: 1411449Smckusick * Our own version of the system qsort routine which is faster by an average 1511449Smckusick * of 25%, with lows and highs of 10% and 50%. 1611449Smckusick * The THRESHold below is the insertion sort threshold, and has been adjusted 1711449Smckusick * for records of size 48 bytes. 1811449Smckusick * The MTHREShold is where we stop finding a better median. 1911449Smckusick */ 201975Swnj 2111449Smckusick #define THRESH 4 /* threshold for insertion */ 2211449Smckusick #define MTHRESH 6 /* threshold for median */ 231975Swnj 2411449Smckusick static int (*qcmp)(); /* the comparison routine */ 2511449Smckusick static int qsz; /* size of each record */ 2611449Smckusick static int thresh; /* THRESHold in chars */ 2711449Smckusick static int mthresh; /* MTHRESHold in chars */ 281975Swnj 2911449Smckusick /* 3011449Smckusick * qsort: 3111449Smckusick * First, set up some global parameters for qst to share. Then, quicksort 3211449Smckusick * with qst(), and then a cleanup insertion sort ourselves. Sound simple? 3311449Smckusick * It's not... 3411449Smckusick */ 351975Swnj 3611449Smckusick qsort(base, n, size, compar) 3711449Smckusick char *base; 3811449Smckusick int n; 3911449Smckusick int size; 4011449Smckusick int (*compar)(); 4111449Smckusick { 4211449Smckusick register char c, *i, *j, *lo, *hi; 4311449Smckusick char *min, *max; 441975Swnj 4511449Smckusick if (n <= 1) 461975Swnj return; 4711449Smckusick qsz = size; 4811449Smckusick qcmp = compar; 4911449Smckusick thresh = qsz * THRESH; 5011449Smckusick mthresh = qsz * MTHRESH; 5111449Smckusick max = base + n * qsz; 5211449Smckusick if (n >= THRESH) { 5311449Smckusick qst(base, max); 5411449Smckusick hi = base + thresh; 5511449Smckusick } else { 5611449Smckusick hi = max; 5711449Smckusick } 5811449Smckusick /* 5911449Smckusick * First put smallest element, which must be in the first THRESH, in 6011449Smckusick * the first position as a sentinel. This is done just by searching 6111449Smckusick * the first THRESH elements (or the first n if n < THRESH), finding 6211449Smckusick * the min, and swapping it into the first position. 6311449Smckusick */ 6411449Smckusick for (j = lo = base; (lo += qsz) < hi; ) 6511449Smckusick if (qcmp(j, lo) > 0) 6611449Smckusick j = lo; 6711449Smckusick if (j != base) { 6811449Smckusick /* swap j into place */ 6911449Smckusick for (i = base, hi = base + qsz; i < hi; ) { 7011449Smckusick c = *j; 7111449Smckusick *j++ = *i; 7211449Smckusick *i++ = c; 7311449Smckusick } 7411449Smckusick } 7511449Smckusick /* 7611449Smckusick * With our sentinel in place, we now run the following hyper-fast 7711449Smckusick * insertion sort. For each remaining element, min, from [1] to [n-1], 7811449Smckusick * set hi to the index of the element AFTER which this one goes. 7911449Smckusick * Then, do the standard insertion sort shift on a character at a time 8011449Smckusick * basis for each element in the frob. 8111449Smckusick */ 8211449Smckusick for (min = base; (hi = min += qsz) < max; ) { 8311449Smckusick while (qcmp(hi -= qsz, min) > 0) 8411449Smckusick /* void */; 8511449Smckusick if ((hi += qsz) != min) { 8611449Smckusick for (lo = min + qsz; --lo >= min; ) { 8711449Smckusick c = *lo; 8811449Smckusick for (i = j = lo; (j -= qsz) >= hi; i = j) 8911449Smckusick *i = *j; 9011449Smckusick *i = c; 911975Swnj } 921975Swnj } 9311449Smckusick } 9411449Smckusick } 951975Swnj 9611449Smckusick /* 9711449Smckusick * qst: 9811449Smckusick * Do a quicksort 9911449Smckusick * First, find the median element, and put that one in the first place as the 10011449Smckusick * discriminator. (This "median" is just the median of the first, last and 10111449Smckusick * middle elements). (Using this median instead of the first element is a big 10211449Smckusick * win). Then, the usual partitioning/swapping, followed by moving the 10311449Smckusick * discriminator into the right place. Then, figure out the sizes of the two 10411449Smckusick * partions, do the smaller one recursively and the larger one via a repeat of 10511449Smckusick * this code. Stopping when there are less than THRESH elements in a partition 10611449Smckusick * and cleaning up with an insertion sort (in our caller) is a huge win. 10711449Smckusick * All data swaps are done in-line, which is space-losing but time-saving. 10811449Smckusick * (And there are only three places where this is done). 10911449Smckusick */ 11011449Smckusick 11111449Smckusick static 11211449Smckusick qst(base, max) 11311449Smckusick char *base, *max; 11411449Smckusick { 11511449Smckusick register char c, *i, *j, *jj; 11611449Smckusick register int ii; 11711449Smckusick char *mid, *tmp; 11811449Smckusick int lo, hi; 11911449Smckusick 12011449Smckusick /* 12111449Smckusick * At the top here, lo is the number of characters of elements in the 12211449Smckusick * current partition. (Which should be max - base). 12311449Smckusick * Find the median of the first, last, and middle element and make 12411449Smckusick * that the middle element. Set j to largest of first and middle. 12511449Smckusick * If max is larger than that guy, then it's that guy, else compare 12611449Smckusick * max with loser of first and take larger. Things are set up to 12711449Smckusick * prefer the middle, then the first in case of ties. 12811449Smckusick */ 12911449Smckusick lo = max - base; /* number of elements as chars */ 13011449Smckusick do { 13111449Smckusick mid = i = base + qsz * ((lo / qsz) >> 1); 13211449Smckusick if (lo >= mthresh) { 13311449Smckusick j = (qcmp((jj = base), i) > 0 ? jj : i); 13411449Smckusick if (qcmp(j, (tmp = max - qsz)) > 0) { 13511449Smckusick /* switch to first loser */ 13611449Smckusick j = (j == jj ? i : jj); 13711449Smckusick if (qcmp(j, tmp) < 0) 13811449Smckusick j = tmp; 1391975Swnj } 14011449Smckusick if (j != i) { 14111449Smckusick ii = qsz; 14211449Smckusick do { 14311449Smckusick c = *i; 14411449Smckusick *i++ = *j; 14511449Smckusick *j++ = c; 14611449Smckusick } while (--ii); 14711449Smckusick } 14811449Smckusick } 14911449Smckusick /* 15011449Smckusick * Semi-standard quicksort partitioning/swapping 15111449Smckusick */ 15211449Smckusick for (i = base, j = max - qsz; ; ) { 15311449Smckusick while (i < mid && qcmp(i, mid) <= 0) 15411449Smckusick i += qsz; 15511449Smckusick while (j > mid) { 15611449Smckusick if (qcmp(mid, j) <= 0) { 15711449Smckusick j -= qsz; 15811449Smckusick continue; 1591975Swnj } 16011449Smckusick tmp = i + qsz; /* value of i after swap */ 16111449Smckusick if (i == mid) { 16211449Smckusick /* j <-> mid, new mid is j */ 16311449Smckusick mid = jj = j; 16411449Smckusick } else { 16511449Smckusick /* i <-> j */ 16611449Smckusick jj = j; 16711449Smckusick j -= qsz; 16811449Smckusick } 16911449Smckusick goto swap; 1701975Swnj } 17111449Smckusick if (i == mid) { 17211449Smckusick break; 1731975Swnj } else { 17411449Smckusick /* i <-> mid, new mid is i */ 17511449Smckusick jj = mid; 17611449Smckusick tmp = mid = i; /* value of i after swap */ 17711449Smckusick j -= qsz; 1781975Swnj } 17911449Smckusick swap: 18011449Smckusick ii = qsz; 18111449Smckusick do { 18211449Smckusick c = *i; 18311449Smckusick *i++ = *jj; 18411449Smckusick *jj++ = c; 18511449Smckusick } while (--ii); 18611449Smckusick i = tmp; 1871975Swnj } 18811449Smckusick /* 18911449Smckusick * Look at sizes of the two partitions, do the smaller 19011449Smckusick * one first by recursion, then do the larger one by 19111449Smckusick * making sure lo is its size, base and max are update 19211449Smckusick * correctly, and branching back. But only repeat 19311449Smckusick * (recursively or by branching) if the partition is 19411449Smckusick * of at least size THRESH. 19511449Smckusick */ 19611449Smckusick i = (j = mid) + qsz; 19711449Smckusick if ((lo = j - base) <= (hi = max - i)) { 19811449Smckusick if (lo >= thresh) 19911449Smckusick qst(base, j); 20011449Smckusick base = i; 20111449Smckusick lo = hi; 20211449Smckusick } else { 20311449Smckusick if (hi >= thresh) 20411449Smckusick qst(i, max); 20511449Smckusick max = j; 20611449Smckusick } 20711449Smckusick } while (lo >= thresh); 2081975Swnj } 209