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