Main Page   Class Hierarchy   Compound List   File List   Compound Members  

iqsort.h

00001 /*
00002 ** Sorting stuff by Dann Corbit and Pete Filandr.
00003 ** (dcorbit@connx.com and pfilandr@mindspring.com)
00004 ** Use it however you like.
00005 */
00006 
00007 //
00008 //  The insertion sort template is used for small partitions.
00009 //  Insertion sort is stable.
00010 //
00011 
00012 template < class e_type >
00013 void insertion_sort(e_type * array, size_t nmemb)
00014 {
00015     e_type temp,
00016           *last,
00017           *first,
00018           *middle;
00019     if (nmemb > 1) {
00020         first = middle = 1 + array;
00021         last = nmemb - 1 + array;
00022         while (first != last) {
00023             ++first;
00024             if ((*(middle) > *(first))) {
00025                 middle = first;
00026             }
00027         }
00028         if ((*(array) > *(middle))) {
00029             ((void) ((temp) = *(array), *(array) = *(middle), *(middle) = (temp)));
00030         }
00031         ++array;
00032         while (array != last) {
00033             first = array++;
00034             if ((*(first) > *(array))) {
00035                 middle = array;
00036                 temp = *middle;
00037                 do {
00038                     *middle-- = *first--;
00039                 } while ((*(first) > *(&temp)));
00040                 *middle = temp;
00041             }
00042         }
00043     }
00044 }
00045 
00046 //
00047 // The median estimate is used to choose pivots for the quicksort algorithm
00048 //
00049 
00050 template < class e_type >
00051 void median_estimate(e_type * array, size_t n)
00052 {
00053     e_type          temp;
00054     long unsigned   lu_seed = 123456789LU;
00055     const size_t    k = ((lu_seed) = 69069 * (lu_seed) + 362437) % --n;
00056     ((void) ((temp) = *(array), *(array) = *(array + k), *(array + k) = (temp)));
00057     if ((*((array + 1)) > *((array)))) {
00058         (temp) = *(array + 1);
00059         if ((*((array + n)) > *((array)))) {
00060             *(array + 1) = *(array);
00061             if ((*(&(temp)) > *((array + n)))) {
00062                 *(array) = *(array + n);
00063                 *(array + n) = (temp);
00064             } else {
00065                 *(array) = (temp);
00066             }
00067         } else {
00068             *(array + 1) = *(array + n);
00069             *(array + n) = (temp);
00070         }
00071     } else {
00072         if ((*((array)) > *((array + n)))) {
00073             if ((*((array + 1)) > *((array + n)))) {
00074                 (temp) = *(array + 1);
00075                 *(array + 1) = *(array + n);
00076                 *(array + n) = *(array);
00077                 *(array) = (temp);
00078             } else {
00079                 ((void) (((temp)) = *((array)), *((array)) = *((array + n)), *((array + n)) = ((temp))));
00080             }
00081         }
00082     }
00083 }
00084 
00085 
00086 //
00087 // This is the heart of the quick sort algorithm used here.
00088 // If the sort is going quadratic, we switch to heap sort.
00089 // If the partition is small, we switch to insertion sort.
00090 //
00091 
00092 template < class e_type >
00093 void qloop(e_type * array, size_t nmemb, size_t d)
00094 {
00095     e_type temp,
00096           *first,
00097           *last;
00098     while (nmemb > 50) {
00099         if (sorted(array, nmemb)) {
00100             return;
00101         }
00102         if (!d--) {
00103             heapsort(array, nmemb);
00104             return;
00105         }
00106         median_estimate(array, nmemb);
00107         first = 1 + array;
00108         last = nmemb - 1 + array;
00109         do {
00110             ++first;
00111         } while ((*(array) > *(first)));
00112         do {
00113             --last;
00114         } while ((*(last) > *(array)));
00115         while (last > first) {
00116             ((void) ((temp) = *(last), *(last) = *(first), *(first) = (temp)));
00117             do {
00118                 ++first;
00119             } while ((*(array) > *(first)));
00120             do {
00121                 --last;
00122             } while ((*(last) > *(array)));
00123         }
00124         ((void) ((temp) = *(array), *(array) = *(last), *(last) = (temp)));
00125         qloop(last + 1, nmemb - 1 + array - last, d);
00126         nmemb = last - array;
00127     }
00128     insertion_sort(array, nmemb);
00129 }
00130 
00131 //
00132 // This heap sort is better than average because it uses Lamont's heap.
00133 //
00134 
00135 template < class e_type >
00136 void heapsort(e_type * array, size_t nmemb)
00137 {
00138     size_t i,
00139            child,
00140            parent;
00141     e_type temp;
00142     if (nmemb > 1) {
00143         i = --nmemb / 2;
00144         do {
00145             {
00146                 (parent) = (i);
00147                 (temp) = (array)[(parent)];
00148                 (child) = (parent) * 2;
00149                 while ((nmemb) > (child)) {
00150                     if ((*((array) + (child) + 1) > *((array) + (child)))) {
00151                         ++(child);
00152                     }
00153                     if ((*((array) + (child)) > *(&(temp)))) {
00154                         (array)[(parent)] = (array)[(child)];
00155                         (parent) = (child);
00156                         (child) *= 2;
00157                     } else {
00158                         --(child);
00159                         break;
00160                     }
00161                 }
00162                 if ((nmemb) == (child) && (*((array) + (child)) > *(&(temp)))) {
00163                     (array)[(parent)] = (array)[(child)];
00164                     (parent) = (child);
00165                 }
00166                 (array)[(parent)] = (temp);
00167             }
00168         } while (i--);
00169         ((void) ((temp) = *(array), *(array) = *(array + nmemb), *(array + nmemb) = (temp)));
00170         for (--nmemb; nmemb; --nmemb) {
00171             {
00172                 (parent) = (0);
00173                 (temp) = (array)[(parent)];
00174                 (child) = (parent) * 2;
00175                 while ((nmemb) > (child)) {
00176                     if ((*((array) + (child) + 1) > *((array) + (child)))) {
00177                         ++(child);
00178                     }
00179                     if ((*((array) + (child)) > *(&(temp)))) {
00180                         (array)[(parent)] = (array)[(child)];
00181                         (parent) = (child);
00182                         (child) *= 2;
00183                     } else {
00184                         --(child);
00185                         break;
00186                     }
00187                 }
00188                 if ((nmemb) == (child) && (*((array) + (child)) > *(&(temp)))) {
00189                     (array)[(parent)] = (array)[(child)];
00190                     (parent) = (child);
00191                 }
00192                 (array)[(parent)] = (temp);
00193             }
00194             ((void) ((temp) = *(array), *(array) = *(array + nmemb), *(array + nmemb) = (temp)));
00195         }
00196     }
00197 }
00198 
00199 // 
00200 // We use this to check to see if a partition is already sorted.
00201 // 
00202 
00203 template < class e_type >
00204 int sorted(e_type * array, size_t nmemb)
00205 {
00206     for (--nmemb; nmemb; --nmemb) {
00207         if ((*(array) > *(array + 1))) {
00208             return 0;
00209         }
00210         ++array;
00211     }
00212     return 1;
00213 }
00214 
00215 // 
00216 // We use this to check to see if a partition is already reverse-sorted.
00217 // 
00218 
00219 template < class e_type >
00220 int             rev_sorted(e_type * array, size_t nmemb)
00221 {
00222     for (--nmemb; nmemb; --nmemb) {
00223         if ((*(array + 1) > *(array))) {
00224             return 0;
00225         }
00226         ++array;
00227     }
00228     return 1;
00229 }
00230 
00231 // 
00232 // We use this to reverse a reverse-sorted partition.
00233 // 
00234 
00235 template < class e_type >
00236 void rev_array(e_type * array, size_t nmemb)
00237 {
00238     e_type          temp,
00239         *end;
00240     for (end = array + nmemb - 1; end > array; ++array) {
00241         ((void) ((temp) = *(array), *(array) = *(end), *(end) = (temp)));
00242         --end;
00243     }
00244 }
00245 
00246 // 
00247 // Introspective quick sort algorithm user entry point.
00248 // You do not need to directly call any other sorting template.
00249 // This sort will perform very well under all circumstances.
00250 // 
00251 
00252 template < class e_type >
00253 void iqsort(e_type * array, size_t nmemb)
00254 {
00255     size_t d,
00256            n;
00257     if (nmemb > 1 && !sorted(array, nmemb)) {
00258         if (!rev_sorted(array, nmemb)) {
00259             n = nmemb / 4;
00260             d = 2;
00261             while (n) {
00262                 ++d;
00263                 n /= 2;
00264             }
00265             qloop(array, nmemb, 2 * d);
00266         } else {
00267             rev_array(array, nmemb);
00268         }
00269     }
00270 }
00271 

Generated on Mon Oct 23 13:23:58 2006 for FastDB by doxygen1.2.18