122102Smckusick /* 222102Smckusick * Copyright (c) 1980 Regents of the University of California. 3*34434Sbostic * All rights reserved. 4*34434Sbostic * 5*34434Sbostic * Redistribution and use in source and binary forms are permitted 6*34434Sbostic * provided that this notice is preserved and that due credit is given 7*34434Sbostic * to the University of California at Berkeley. The name of the University 8*34434Sbostic * may not be used to endorse or promote products derived from this 9*34434Sbostic * software without specific written prior permission. This software 10*34434Sbostic * is provided ``as is'' without express or implied warranty. 1122102Smckusick */ 121975Swnj 1326577Sdonn #if defined(LIBC_SCCS) && !defined(lint) 14*34434Sbostic static char sccsid[] = "@(#)qsort.c 5.3 (Berkeley) 05/23/88"; 15*34434Sbostic #endif /* LIBC_SCCS and not lint */ 1622102Smckusick 1711449Smckusick /* 1811449Smckusick * qsort.c: 1911449Smckusick * Our own version of the system qsort routine which is faster by an average 2011449Smckusick * of 25%, with lows and highs of 10% and 50%. 2111449Smckusick * The THRESHold below is the insertion sort threshold, and has been adjusted 2211449Smckusick * for records of size 48 bytes. 2311449Smckusick * The MTHREShold is where we stop finding a better median. 2411449Smckusick */ 251975Swnj 2611449Smckusick #define THRESH 4 /* threshold for insertion */ 2711449Smckusick #define MTHRESH 6 /* threshold for median */ 281975Swnj 2911449Smckusick static int (*qcmp)(); /* the comparison routine */ 3011449Smckusick static int qsz; /* size of each record */ 3111449Smckusick static int thresh; /* THRESHold in chars */ 3211449Smckusick static int mthresh; /* MTHRESHold in chars */ 331975Swnj 3411449Smckusick /* 3511449Smckusick * qsort: 3611449Smckusick * First, set up some global parameters for qst to share. Then, quicksort 3711449Smckusick * with qst(), and then a cleanup insertion sort ourselves. Sound simple? 3811449Smckusick * It's not... 3911449Smckusick */ 401975Swnj 4111449Smckusick qsort(base, n, size, compar) 4211449Smckusick char *base; 4311449Smckusick int n; 4411449Smckusick int size; 4511449Smckusick int (*compar)(); 4611449Smckusick { 4711449Smckusick register char c, *i, *j, *lo, *hi; 4811449Smckusick char *min, *max; 491975Swnj 5011449Smckusick if (n <= 1) 511975Swnj return; 5211449Smckusick qsz = size; 5311449Smckusick qcmp = compar; 5411449Smckusick thresh = qsz * THRESH; 5511449Smckusick mthresh = qsz * MTHRESH; 5611449Smckusick max = base + n * qsz; 5711449Smckusick if (n >= THRESH) { 5811449Smckusick qst(base, max); 5911449Smckusick hi = base + thresh; 6011449Smckusick } else { 6111449Smckusick hi = max; 6211449Smckusick } 6311449Smckusick /* 6411449Smckusick * First put smallest element, which must be in the first THRESH, in 6511449Smckusick * the first position as a sentinel. This is done just by searching 6611449Smckusick * the first THRESH elements (or the first n if n < THRESH), finding 6711449Smckusick * the min, and swapping it into the first position. 6811449Smckusick */ 6911449Smckusick for (j = lo = base; (lo += qsz) < hi; ) 7011449Smckusick if (qcmp(j, lo) > 0) 7111449Smckusick j = lo; 7211449Smckusick if (j != base) { 7311449Smckusick /* swap j into place */ 7411449Smckusick for (i = base, hi = base + qsz; i < hi; ) { 7511449Smckusick c = *j; 7611449Smckusick *j++ = *i; 7711449Smckusick *i++ = c; 7811449Smckusick } 7911449Smckusick } 8011449Smckusick /* 8111449Smckusick * With our sentinel in place, we now run the following hyper-fast 8211449Smckusick * insertion sort. For each remaining element, min, from [1] to [n-1], 8311449Smckusick * set hi to the index of the element AFTER which this one goes. 8411449Smckusick * Then, do the standard insertion sort shift on a character at a time 8511449Smckusick * basis for each element in the frob. 8611449Smckusick */ 8711449Smckusick for (min = base; (hi = min += qsz) < max; ) { 8811449Smckusick while (qcmp(hi -= qsz, min) > 0) 8911449Smckusick /* void */; 9011449Smckusick if ((hi += qsz) != min) { 9111449Smckusick for (lo = min + qsz; --lo >= min; ) { 9211449Smckusick c = *lo; 9311449Smckusick for (i = j = lo; (j -= qsz) >= hi; i = j) 9411449Smckusick *i = *j; 9511449Smckusick *i = c; 961975Swnj } 971975Swnj } 9811449Smckusick } 9911449Smckusick } 1001975Swnj 10111449Smckusick /* 10211449Smckusick * qst: 10311449Smckusick * Do a quicksort 10411449Smckusick * First, find the median element, and put that one in the first place as the 10511449Smckusick * discriminator. (This "median" is just the median of the first, last and 10611449Smckusick * middle elements). (Using this median instead of the first element is a big 10711449Smckusick * win). Then, the usual partitioning/swapping, followed by moving the 10811449Smckusick * discriminator into the right place. Then, figure out the sizes of the two 10911449Smckusick * partions, do the smaller one recursively and the larger one via a repeat of 11011449Smckusick * this code. Stopping when there are less than THRESH elements in a partition 11111449Smckusick * and cleaning up with an insertion sort (in our caller) is a huge win. 11211449Smckusick * All data swaps are done in-line, which is space-losing but time-saving. 11311449Smckusick * (And there are only three places where this is done). 11411449Smckusick */ 11511449Smckusick 11611449Smckusick static 11711449Smckusick qst(base, max) 11811449Smckusick char *base, *max; 11911449Smckusick { 12011449Smckusick register char c, *i, *j, *jj; 12111449Smckusick register int ii; 12211449Smckusick char *mid, *tmp; 12311449Smckusick int lo, hi; 12411449Smckusick 12511449Smckusick /* 12611449Smckusick * At the top here, lo is the number of characters of elements in the 12711449Smckusick * current partition. (Which should be max - base). 12811449Smckusick * Find the median of the first, last, and middle element and make 12911449Smckusick * that the middle element. Set j to largest of first and middle. 13011449Smckusick * If max is larger than that guy, then it's that guy, else compare 13111449Smckusick * max with loser of first and take larger. Things are set up to 13211449Smckusick * prefer the middle, then the first in case of ties. 13311449Smckusick */ 13411449Smckusick lo = max - base; /* number of elements as chars */ 13511449Smckusick do { 13611449Smckusick mid = i = base + qsz * ((lo / qsz) >> 1); 13711449Smckusick if (lo >= mthresh) { 13811449Smckusick j = (qcmp((jj = base), i) > 0 ? jj : i); 13911449Smckusick if (qcmp(j, (tmp = max - qsz)) > 0) { 14011449Smckusick /* switch to first loser */ 14111449Smckusick j = (j == jj ? i : jj); 14211449Smckusick if (qcmp(j, tmp) < 0) 14311449Smckusick j = tmp; 1441975Swnj } 14511449Smckusick if (j != i) { 14611449Smckusick ii = qsz; 14711449Smckusick do { 14811449Smckusick c = *i; 14911449Smckusick *i++ = *j; 15011449Smckusick *j++ = c; 15111449Smckusick } while (--ii); 15211449Smckusick } 15311449Smckusick } 15411449Smckusick /* 15511449Smckusick * Semi-standard quicksort partitioning/swapping 15611449Smckusick */ 15711449Smckusick for (i = base, j = max - qsz; ; ) { 15811449Smckusick while (i < mid && qcmp(i, mid) <= 0) 15911449Smckusick i += qsz; 16011449Smckusick while (j > mid) { 16111449Smckusick if (qcmp(mid, j) <= 0) { 16211449Smckusick j -= qsz; 16311449Smckusick continue; 1641975Swnj } 16511449Smckusick tmp = i + qsz; /* value of i after swap */ 16611449Smckusick if (i == mid) { 16711449Smckusick /* j <-> mid, new mid is j */ 16811449Smckusick mid = jj = j; 16911449Smckusick } else { 17011449Smckusick /* i <-> j */ 17111449Smckusick jj = j; 17211449Smckusick j -= qsz; 17311449Smckusick } 17411449Smckusick goto swap; 1751975Swnj } 17611449Smckusick if (i == mid) { 17711449Smckusick break; 1781975Swnj } else { 17911449Smckusick /* i <-> mid, new mid is i */ 18011449Smckusick jj = mid; 18111449Smckusick tmp = mid = i; /* value of i after swap */ 18211449Smckusick j -= qsz; 1831975Swnj } 18411449Smckusick swap: 18511449Smckusick ii = qsz; 18611449Smckusick do { 18711449Smckusick c = *i; 18811449Smckusick *i++ = *jj; 18911449Smckusick *jj++ = c; 19011449Smckusick } while (--ii); 19111449Smckusick i = tmp; 1921975Swnj } 19311449Smckusick /* 19411449Smckusick * Look at sizes of the two partitions, do the smaller 19511449Smckusick * one first by recursion, then do the larger one by 19611449Smckusick * making sure lo is its size, base and max are update 19711449Smckusick * correctly, and branching back. But only repeat 19811449Smckusick * (recursively or by branching) if the partition is 19911449Smckusick * of at least size THRESH. 20011449Smckusick */ 20111449Smckusick i = (j = mid) + qsz; 20211449Smckusick if ((lo = j - base) <= (hi = max - i)) { 20311449Smckusick if (lo >= thresh) 20411449Smckusick qst(base, j); 20511449Smckusick base = i; 20611449Smckusick lo = hi; 20711449Smckusick } else { 20811449Smckusick if (hi >= thresh) 20911449Smckusick qst(i, max); 21011449Smckusick max = j; 21111449Smckusick } 21211449Smckusick } while (lo >= thresh); 2131975Swnj } 214