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