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
1.5.6