Stxxl
1.4.0
|
00001 /*************************************************************************** 00002 * include/stxxl/bits/algo/intksort.h 00003 * 00004 * Part of the STXXL. See http://stxxl.sourceforge.net 00005 * 00006 * Copyright (C) 2002 Peter Sanders <sanders@mpi-sb.mpg.de> 00007 * 00008 * Distributed under the Boost Software License, Version 1.0. 00009 * (See accompanying file LICENSE_1_0.txt or copy at 00010 * http://www.boost.org/LICENSE_1_0.txt) 00011 **************************************************************************/ 00012 00013 #ifndef STXXL_INTKSORT_HEADER 00014 #define STXXL_INTKSORT_HEADER 00015 00016 #include <algorithm> 00017 #include <cassert> 00018 #include <stxxl/bits/common/types.h> 00019 #include <stxxl/bits/unused.h> 00020 #include <stxxl/bits/parallel.h> 00021 00022 00023 __STXXL_BEGIN_NAMESPACE 00024 00025 template <typename type_key> 00026 static void 00027 count(type_key * a, type_key * aEnd, int_type * bucket, int_type K, typename type_key::key_type offset, 00028 unsigned shift) 00029 { 00030 // reset buckets 00031 std::fill(bucket, bucket + K, 0); 00032 00033 // count occupancies 00034 for (type_key * p = a; p < aEnd; p++) 00035 { 00036 int_type i = (p->key - offset) >> shift; 00037 /* 00038 if (!(i < K && i >= 0)) 00039 { 00040 STXXL_ERRMSG("i: " << i); 00041 abort(); 00042 } 00043 */ 00044 bucket[i]++; 00045 } 00046 } 00047 00048 00049 static void 00050 exclusive_prefix_sum(int_type * bucket, int_type K) 00051 { 00052 int_type sum = 0; 00053 for (int_type i = 0; i < K; i++) 00054 { 00055 int_type current = bucket[i]; 00056 bucket[i] = sum; 00057 sum += current; 00058 } 00059 } 00060 00061 00062 // distribute input a to output b using bucket for the starting indices 00063 template <typename type_key> 00064 static void 00065 classify(type_key * a, type_key * aEnd, type_key * b, int_type * bucket, typename type_key::key_type offset, unsigned shift) 00066 { 00067 for (type_key * p = a; p < aEnd; p++) 00068 { 00069 int_type i = (p->key - offset) >> shift; 00070 int_type bi = bucket[i]; 00071 b[bi] = *p; 00072 bucket[i] = bi + 1; 00073 } 00074 } 00075 00076 00077 template <class T> 00078 inline void 00079 sort2(T & a, T & b) 00080 { 00081 if (b < a) 00082 std::swap(a, b); 00083 } 00084 00085 template <class T> 00086 inline void 00087 sort3(T & a, T & b, T & c) 00088 { 00089 T temp; 00090 if (b < a) 00091 { 00092 if (c < a) 00093 { // b , c < a 00094 if (b < c) 00095 { // b < c < a 00096 temp = a; 00097 a = b; 00098 b = c; 00099 c = temp; 00100 } 00101 else 00102 { // c <=b < a 00103 std::swap(c, a); 00104 } 00105 } 00106 else 00107 { // b < a <=c 00108 std::swap(a, b); 00109 } 00110 } 00111 else 00112 { // a <=b 00113 if (c < a) 00114 { // c < a <=b 00115 temp = a; 00116 a = c; 00117 c = b; 00118 b = temp; 00119 } 00120 else 00121 { // a <=b , c 00122 if (c < b) 00123 { // a <=c < b 00124 std::swap(b, c); 00125 } 00126 } 00127 } 00128 // Assert1 (!(b < a) && !(c < b)); 00129 } 00130 00131 00132 template <class T> 00133 inline void 00134 sort4(T & a, T & b, T & c, T & d) 00135 { 00136 sort2(a, b); 00137 sort2(c, d); // a < b ; c < d 00138 if (c < a) 00139 { // c minimal, a < b 00140 if (d < a) 00141 { // c < d < a < b 00142 std::swap(a, c); 00143 std::swap(b, d); 00144 } 00145 else 00146 { // c < a < {db} 00147 if (d < b) 00148 { // c < a < d < b 00149 T temp = a; 00150 a = c; 00151 c = d; 00152 d = b; 00153 b = temp; 00154 } 00155 else 00156 { // c < a < b < d 00157 T temp = a; 00158 a = c; 00159 c = b; 00160 b = temp; 00161 } 00162 } 00163 } 00164 else 00165 { // a minimal ; c < d 00166 if (c < b) 00167 { // c < (bd) 00168 if (d < b) 00169 { // c < d < b 00170 T temp = b; 00171 b = c; 00172 c = d; 00173 d = temp; 00174 } 00175 else 00176 { // a < c < b < d 00177 std::swap(b, c); 00178 } 00179 } // else sorted 00180 } 00181 //Assert1 (!(b < a) && !(c < b) & !(d < c)); 00182 } 00183 00184 00185 template <class T> 00186 inline void 00187 sort5(T & a, T & b, T & c, T & d, T & e) 00188 { 00189 sort2(a, b); 00190 sort2(d, e); 00191 if (d < a) 00192 { 00193 std::swap(a, d); 00194 std::swap(b, e); 00195 } // a < d < e, a < b 00196 if (d < c) 00197 { 00198 std::swap(c, d); // a minimal, c < {de} 00199 sort2(d, e); 00200 } 00201 else 00202 { // a<b, a<d<e, c<d<e 00203 sort2(a, c); 00204 } // a min, c < d < e 00205 // insert b int cde by binary search 00206 if (d < b) 00207 { // c < d < {be} 00208 if (e < b) 00209 { // c < d < e < b 00210 T temp = b; 00211 b = c; 00212 c = d; 00213 d = e; 00214 e = temp; 00215 } 00216 else 00217 { // c < d < b < e 00218 T temp = b; 00219 b = c; 00220 c = d; 00221 d = temp; 00222 } 00223 } 00224 else 00225 { // {cb} <=d < e 00226 sort2(b, c); 00227 } 00228 //Assert1 (!(b < a) && !(c < b) & !(d < c) & !(e < d)); 00229 } 00230 00231 00232 template <class T> 00233 inline void 00234 insertion_sort(T * a, T * aEnd) 00235 { 00236 T * pp; 00237 for (T * p = a + 1; p < aEnd; p++) 00238 { 00239 // Invariant a..p-1 is sorted; 00240 T t = *p; 00241 if (t < *a) 00242 { // new minimum 00243 // move stuff to the right 00244 for (pp = p; pp != a; pp--) 00245 { 00246 *pp = *(pp - 1); 00247 } 00248 *pp = t; 00249 } 00250 else 00251 { 00252 // now we can use *a as a sentinel 00253 for (pp = p; t < *(pp - 1); pp--) 00254 { 00255 *pp = *(pp - 1); 00256 } 00257 *pp = t; 00258 } 00259 } 00260 } 00261 00262 // sort each bucket 00263 // bucket[i] is an index one off to the right from 00264 // the end of the i-th bucket 00265 template <class T> 00266 static void 00267 cleanup(T * b, int_type * bucket, int_type K) 00268 { 00269 T * c = b; 00270 for (int_type i = 0; i < K; i++) 00271 { 00272 T * cEnd = b + bucket[i]; 00273 switch (cEnd - c) 00274 { 00275 case 0: 00276 break; 00277 case 1: 00278 break; 00279 case 2: 00280 sort2(c[0], c[1]); 00281 break; 00282 case 3: 00283 sort3(c[0], c[1], c[2]); 00284 break; 00285 case 4: 00286 sort4(c[0], c[1], c[2], c[3]); 00287 break; 00288 case 5: 00289 #if 0 00290 sort5(c[0], c[1], c[2], c[3], c[4]); 00291 break; 00292 #endif 00293 case 6: 00294 case 7: 00295 case 8: 00296 case 9: 00297 case 10: 00298 case 11: 00299 case 12: 00300 case 13: 00301 case 14: 00302 case 15: 00303 case 16: 00304 insertion_sort(c, cEnd); 00305 break; 00306 default: 00307 check_sort_settings(); 00308 potentially_parallel:: 00309 sort(c, cEnd); 00310 } 00311 c = cEnd; 00312 } 00313 } 00314 00315 // do a single level MDS radix sort 00316 // using bucket[0..K-1] as a counter array 00317 // and using (key(x) - offset) >> shift to index buckets. 00318 // and using (key(x) - offset) >> shift to index buckets. 00319 // the input comes from a..aEnd-1 00320 // the output goes to b 00321 template <typename type_key> 00322 void 00323 l1sort(type_key * a, 00324 type_key * aEnd, 00325 type_key * b, int_type * bucket, int_type K, typename type_key::key_type offset, int shift) 00326 { 00327 count(a, aEnd, bucket, K, offset, shift); 00328 exclusive_prefix_sum(bucket, K); 00329 classify(a, aEnd, b, bucket, offset, shift); 00330 cleanup(b, bucket, K); 00331 } 00332 00333 template <typename type, typename type_key, typename key_extractor> 00334 void classify_block(type * begin, type * end, type_key * & out, 00335 int_type * bucket, typename key_extractor::key_type offset, unsigned shift, key_extractor keyobj) 00336 { 00337 assert(shift < (sizeof(typename key_extractor::key_type) * 8 + 1)); 00338 for (type * p = begin; p < end; p++, out++) // count & create references 00339 { 00340 out->ptr = p; 00341 typename key_extractor::key_type key = keyobj(*p); 00342 int_type ibucket = (key - offset) >> shift; 00343 out->key = key; 00344 bucket[ibucket]++; 00345 } 00346 } 00347 template <typename type, typename type_key, typename key_extractor> 00348 void classify_block(type * begin, type * end, type_key * & out, int_type * bucket, typename type::key_type offset, unsigned shift, 00349 const int_type K, key_extractor keyobj) 00350 { 00351 assert(shift < (sizeof(typename type::key_type) * 8 + 1)); 00352 for (type * p = begin; p < end; p++, out++) // count & create references 00353 { 00354 out->ptr = p; 00355 typename type::key_type key = keyobj(*p); 00356 int_type ibucket = (key - offset) >> shift; 00357 /* 00358 if (!(ibucket < K && ibucket >= 0)) 00359 { 00360 STXXL_ERRMSG("ibucket: " << ibucket << " K:" << K); 00361 abort(); 00362 } 00363 */ 00364 out->key = key; 00365 bucket[ibucket]++; 00366 } 00367 STXXL_UNUSED(K); 00368 } 00369 00370 __STXXL_END_NAMESPACE 00371 00372 #endif // !STXXL_INTKSORT_HEADER