sort.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------- *\
00002    file: sort.cpp
00003    auth: Travis Fischer
00004    acct: tfischer
00005    date: 3/18/2007
00006          9/17/2008
00007    
00008       Implementations of radix sort and randomized 
00009    quicksort, which are templated to handle sorting 
00010    arrays of builtin signed / unsigned ints, floats, 
00011    and doubles.
00012       Quicksort should handle sorting arrays of any 
00013    type implementing the inequality operator (<=).
00014       The radix sort routines assume standard sizes 
00015    for builtin types on a a 32-bit platform.  
00016    Specifically, they assume 32-bit floats / ints / 
00017    longs and 64-bit doubles / long longs.
00018       Radix sort runs in O(n), whereas randomized 
00019    quicksort runs in O(nlog n) but is more generic.
00020 \* ---------------------------------------------- */
00021 
00022 #include "sort.h"
00023 #include <common.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <stdio.h>
00027 
00028 #include <boost/static_assert.hpp>
00029 
00030 BOOST_STATIC_ASSERT(sizeof(unsigned int) == sizeof(int));
00031 BOOST_STATIC_ASSERT(sizeof(unsigned int) == sizeof(float));
00032 BOOST_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(double));
00033 
00034 BOOST_STATIC_ASSERT(std::numeric_limits<unsigned int>::digits == 32);
00035 BOOST_STATIC_ASSERT(std::numeric_limits<unsigned long long>::digits == 64);
00036 
00037 
00038 /// @see http://www.stereopsis.com/radix.html for notes which inspired these 
00039 /// floating point radix sort implementations
00040 
00041 // assumes 32 bit floats and unsigned ints
00042 #define FLIP_FLOAT(f)                              \
00043    (f) ^ (-((f) >> 31) | 0x80000000)
00044 
00045 #define FLIP_FLOAT_INVERSE(f)                      \
00046    (f) ^ ((((f) >> 31) - 1) | 0x80000000)
00047 
00048 // assumes 64 bit doubles and unsigned long longs
00049 #define FLIP_DOUBLE(d)                             \
00050    (d) ^ (-((d) >> 63) | 0x800000000000000ULL)
00051 
00052 #define FLIP_DOUBLE_INVERSE(d)                     \
00053    (d) ^ ((((d) >> 63) - 1) | 0x800000000000000ULL)
00054 
00055 template <typename T>
00056 static inline void stableSort(const T *restrict a, T *restrict b, 
00057                               const unsigned int n, const T mask, 
00058                               const unsigned int shift);
00059 template <typename T>
00060 static inline void stableSortIndices(
00061                               const T *restrict a, 
00062                               unsigned int *restrict indices, 
00063                               unsigned int *restrict b, 
00064                               const unsigned int n, const T mask, 
00065                               const unsigned int shift);
00066 // For randomized quicksort
00067 static inline unsigned int randNum(unsigned int limit);
00068 static inline int randNo(int low, int high);
00069 
00070 #define SWAP(x, y) \
00071    do {            \
00072       (x) ^= (y);  \
00073       (y) ^= (x);  \
00074       (x) ^= (y);  \
00075    } while(0)
00076 
00077 // Expected O(nlog n).  Worse-Case O(n^2)
00078 // p and q are inclusive
00079 // Ex:  quickSort(array, 0, size - 1);
00080 template <typename T>
00081 void quickSort(T *a, const int p, const int q) {
00082    if (p >= q)
00083       return;
00084    
00085    int pivot = randNo(p, q);
00086    const T pivotVal = a[pivot];
00087    int left = p, right = q;
00088   
00089    // ensure pivot appears in left-most position
00090    if (pivot != left)
00091       SWAP(a[pivot], a[left]);
00092    
00093    ++left;
00094    
00095    // swap elements appearing in wrong pos w/ relation to pivotVal
00096    while(left < right) {
00097       while(a[left] <= pivotVal && left < right)
00098          ++left;
00099       
00100       while(a[right] > pivotVal)// && left <= right)
00101          --right;
00102       
00103       if (left < right)
00104          SWAP(a[left], a[right]);
00105    }
00106    
00107    if (a[right] < a[p])
00108       SWAP(a[right], a[p]);
00109    
00110    quickSort<T>(a, p, right - 1);
00111    quickSort<T>(a, right + 1, q);
00112 }
00113 
00114 // generic radix sort for 32-bit unsigned integers
00115 template <>
00116 void radixSort(unsigned int *a, unsigned int *b, const unsigned int n) {
00117    // temporary scratch buffer
00118    const unsigned int mask = 0xff;
00119    unsigned int i;
00120    
00121    for(i = 0; i < sizeof(int) << 3; i += 8) {
00122       stableSort<unsigned int>(a, b, n, mask << i, i);
00123       
00124       unsigned int *temp = a;
00125       a = b;
00126       b = temp;
00127    }
00128 }
00129 
00130 // radix sort specialized for 32-bit signed integers
00131 template <>
00132 void radixSort(int *a, int *b, const unsigned int n) {
00133    // temporary scratch buffer
00134    unsigned int *c = (unsigned int*)a;
00135    const unsigned int mask = 0xff;
00136    unsigned int i;
00137    
00138    // always flip sign bit; search 2's complement online for more info
00139    for(i = n; i--;)
00140       c[i] ^= 0x80000000;
00141    
00142    for(i = 0; i < sizeof(int) << 3; i += 8) {
00143       stableSort<unsigned int>((unsigned int*)a, (unsigned int*)b, 
00144                                n, mask << i, i);
00145       
00146       int *temp = a;
00147       a = b;
00148       b = temp;
00149    }
00150    
00151    // flip sign bit back
00152    for(i = n; i--;)
00153       c[i] ^= 0x80000000;
00154 }
00155 
00156 // radix sort specialized for single precision floating point numbers
00157 template <>
00158 void radixSort(float *a, float *b, const unsigned int n) {
00159    // temporary scratch buffer
00160    unsigned int *c = (unsigned int*)a;
00161    const unsigned int mask = 0xff;
00162    unsigned int i;
00163    
00164    for(i = n; i--;)
00165       c[i] = FLIP_FLOAT(c[i]);
00166    
00167    for(i = 0; i < sizeof(float) << 3; i += 8) {
00168       stableSort<unsigned int>((unsigned int*)a, (unsigned int*)b, 
00169                                n, mask << i, i);
00170       
00171       float *temp = a;
00172       a = b;
00173       b = temp;
00174    }
00175    
00176    for(i = n; i--;)
00177       c[i] = FLIP_FLOAT_INVERSE(c[i]);
00178 }
00179 
00180 // radix sort specialized for double precision floating point numbers
00181 template <>
00182 void radixSort(double *a, double *b, const unsigned int n) {
00183    // temporary scratch buffer
00184    unsigned long long *c = (unsigned long long*)a;
00185    const unsigned long long mask = 0xff;
00186    unsigned int i;
00187    
00188    for(i = n; i--;)
00189       c[i] = FLIP_DOUBLE(c[i]);
00190    
00191    for(i = 0; i < sizeof(double) << 3; i += 8) {
00192       stableSort<unsigned long long>((unsigned long long*)a, 
00193                                      (unsigned long long*)b, 
00194                                      n, mask << i, i);
00195       
00196       double *temp = a;
00197       a = b;
00198       b = temp;
00199    }
00200    
00201    for(i = n; i--;)
00202       c[i] = FLIP_DOUBLE_INVERSE(c[i]);
00203 }
00204 
00205 // Stable counting sort used as a subroutine in radix sort
00206 // returns a sorted in b with respect to the bits specified 
00207 //    by (mask << shift)
00208 template <typename T>
00209 static inline void stableSort(const T *restrict a, T *restrict b, 
00210                               const unsigned int n, const T mask, 
00211                               const unsigned int shift)
00212 {
00213    static unsigned int c[256];
00214    unsigned int i;
00215    
00216    bzero(c, sizeof(unsigned int) * 256);
00217    for(i = 0; i < n; ++i)
00218       ++c[(a[i] & mask) >> shift];
00219    
00220    // check if input array is already sorted with respect to the current mask
00221    /*for(i = 0; i < n; ++k) {
00222       if (c[(a[i] & mask) >> shift] == n) {
00223          memcpy(a, b, sizeof(T) * n);
00224          return;
00225       }
00226    }*/
00227    
00228    // compute partial sums
00229    for(i = 1; i < 256; ++i)
00230       c[i] += c[i - 1];
00231    
00232    // place elements of a into b in sorted order
00233    // by knowing the number of elements less than a[i], 
00234    // we know the index of where a[i] needs to appear in b
00235    for(i = n; i--;) {
00236       const T temp = a[i];
00237       
00238       // decrement c to accomodate for duplicates
00239       b[--c[(temp & mask) >> shift]] = temp;
00240    }
00241 }
00242 
00243 // For randomized quicksort
00244 static inline unsigned int randNum(unsigned int limit) {
00245    if (limit <= 0)
00246       return 0;
00247 
00248    return rand() % limit;
00249 }
00250 
00251 // For randomized quicksort
00252 static inline int randNo(int low, int high) { // inclusive
00253    return (low + randNum(high - low));
00254 }
00255 
00256 
00257 // radix sort specialized for unsigned integers
00258 template <>
00259 void radixSortIndices(unsigned int *a, unsigned int *indices, unsigned int *b, 
00260                      const unsigned int n)
00261 {
00262    unsigned int *c = (unsigned int*)a;
00263    const unsigned long long mask = 0xff;
00264    unsigned int i;
00265    
00266    for(i = 0; i < sizeof(double) << 3; i += 8) {
00267       stableSortIndices<unsigned int>(c, indices, b, n, mask << i, i);
00268 
00269       unsigned int *temp = b;
00270       b = indices;
00271       indices = temp;
00272    }
00273 }
00274 
00275 // radix sort specialized for double precision floating point numbers
00276 template <>
00277 void radixSortIndices(double *a, unsigned int *indices, unsigned int *b, 
00278                      const unsigned int n)
00279 {
00280    unsigned long long *c = (unsigned long long*)a;
00281    const unsigned long long mask = 0xff;
00282    unsigned int i;
00283    
00284    for(i = n; i--;) {
00285       c[i] = FLIP_DOUBLE(c[i]);
00286       indices[i] = i; // TODO: take out?
00287    }
00288    
00289    for(i = 0; i < sizeof(double) << 3; i += 8) {
00290       stableSortIndices<unsigned long long>(c, indices, b, n, mask << i, i);
00291       
00292       unsigned int *temp = b;
00293       b = indices;
00294       indices = temp;
00295    }
00296    
00297    for(i = n; i--;)
00298       c[i] = FLIP_DOUBLE_INVERSE(c[i]);
00299 }
00300 
00301 // Stable counting sort used as a subroutine in radix sort
00302 // returns a sorted in b with respect to the bits specified 
00303 //    by (mask << shift)
00304 template <typename T>
00305 static inline void stableSortIndices(const T *restrict a, 
00306                                      unsigned int *restrict indices, 
00307                                      unsigned int *restrict b, 
00308                                      const unsigned int n, const T mask, 
00309                                      const unsigned int shift)
00310 {
00311    static unsigned int c[256];
00312    unsigned int i;
00313    
00314    bzero(c, sizeof(unsigned int) * 256);
00315    for(i = 0; i < n; ++i)
00316       ++c[(a[i] & mask) >> shift];
00317    
00318    // compute partial sums
00319    for(i = 1; i < 256; ++i)
00320       c[i] += c[i - 1];
00321    
00322    // place elements of a into b in sorted order.
00323    // by knowing the number of elements less than a[i], 
00324    // we know the index of where a[i] needs to appear in b
00325    for(i = n; i--;) {
00326       const unsigned int oldIndex = indices[i];
00327       
00328       // decrement c to accomodate for duplicates
00329       b[--c[(a[oldIndex] & mask) >> shift]] = oldIndex;
00330    }
00331 }
00332 
00333 #undef restrict
00334 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6