home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- myqsort.c
-
- This reentrant and reusable module implements a fast quicksort algorithm.
-
- Original version by Haydn Huntley. Modified to support reentrancy and
- error handling (e.g., user cancels) by John Norstad.
- ----------------------------------------------------------------------------*/
-
- #include <stdlib.h>
- #include "myqsort.h"
-
- typedef struct TSortInfo {
- long size;
- SortCmpFunction cmp;
- } TSortInfo;
-
-
-
- /*----------------------------------------------------------------------------
- MemSwap
-
- Exchange two array elements.
-
- Entry: p = pointer to first element.
- q = pointer to second element.
- size = size of elements.
- ----------------------------------------------------------------------------*/
-
- static void MemSwap (register char *p, register char *q,
- register long size)
- {
- register char tmp;
-
- while (size--) {
- tmp = *p;
- *p++ = *q;
- *q++ = tmp;
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- ChooseMedian
-
- Select the median of three array elements and swap it with a destination
- element.
-
- Entry: pDest = pointer to destination element.
- pA, pB, pC = pointer to three elements.
- sortInfo = pointer to sort info.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr ChooseMedian (void *pDest, void *pA, void *pB, void *pC,
- TSortInfo *sortInfo)
- {
- register void *pMedian;
- register SortCmpFunction cmp;
- short result;
- OSErr err;
-
- cmp = sortInfo->cmp;
- err = (*cmp)(pA, pB, &result);
- if (err != noErr) return err;
- if (result > 0) { /* pA > pB, what is pC? */
- err = (*cmp)(pA, pC, &result);
- if (err != noErr) return err;
- if (result > 0) { /* pA > pB, pA > pC */
- err = (*cmp)(pB, pC, &result);
- if (err != noErr) return err;
- if (result > 0)
- pMedian = pB; /* pA > pB > pC */
- else
- pMedian = pC; /* pA > pC > pB */
- } else {
- pMedian = pA; /* pC > pA > pB */
- }
- } else { /* pB > pA, what is pC? */
- err = (*cmp)(pA, pC, &result);
- if (err != noErr) return err;
- if (result > 0) {
- pMedian = pA; /* pB > pA > pC */
- } else { /* pB > pA, pC > pA */
- err = (*cmp)(pB, pC, &result);
- if (err != noErr) return err;
- if (result > 0)
- pMedian = pC; /* pB > pC > pA */
- else
- pMedian = pB; /* pC > pB > pA */
- }
- }
- if (pDest != pMedian) MemSwap(pDest, pMedian, sortInfo->size);
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoFastQSort
-
- Entry: first = pointer to first element
- of array in range to be sorted.
- last = pointer to element following last element
- of array in range to be sorted.
- sortInfo = pointer to sort info.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoFastQSort (register char *first, char *last, TSortInfo *sortInfo)
- {
- register SortCmpFunction cmp;
- register char *i, *j;
- register long n, size;
- OSErr err;
- short result;
-
- size = sortInfo->size;
- cmp = sortInfo->cmp;
- while ((n = (last - first) / size) > 1) {
- if (n < 25) {
- MemSwap(first + (rand() % n) * size, first, size);
- } else {
- err = ChooseMedian(first, first, first + (n / 2) * size,
- first + (rand() % n) * size, sortInfo);
- if (err != noErr) return err;
- }
- i = first;
- j = last;
- while (true) {
- i += size;
- while (i < last) {
- err = (*cmp)(i, first, &result);
- if (err != noErr) return err;
- if (result >= 0) break;
- i += size;
- }
- j -= size;
- while (j > first) {
- err = (*cmp)(j, first, &result);
- if (err != noErr) return err;
- if (result <= 0) break;
- j -= size;
- }
- if (i >= j) break;
- MemSwap(i, j, size);
- }
- if (j == first) {
- first += size;
- continue;
- }
- MemSwap(first, j, size);
- if (j - first < last - (j + size)) {
- err = DoFastQSort(first, j, sortInfo);
- if (err != noErr) return err;
- first = j + size;
- } else {
- err = DoFastQSort(j + size, last, sortInfo);
- if (err != noErr) return err;
- last = j;
- }
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- FastQSort
-
- Sort an array.
-
- Entry: base = pointer to first array element.
- n = number of array elements.
- size = size of array elements.
- cmp = pointer to array element comparison function.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr FastQSort (void *base, long n, long size, SortCmpFunction cmp)
- {
- TSortInfo sortInfo;
-
- srand(TickCount());
-
- sortInfo.cmp = cmp;
- sortInfo.size = size;
-
- return DoFastQSort(base, (char*)base + n * size, &sortInfo);
- }
-