pelib
2.0.0
|
00001 /* 00002 * sort.c 00003 * 00004 * Created on: 25 Jan 2012 00005 * Copyright 2012 Nicolas Melot 00006 * 00007 * This file is part of pelib. 00008 * 00009 * pelib is free software: you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation, either version 3 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * pelib is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with pelib. If not, see <http://www.gnu.org/licenses/>. 00021 * 00022 */ 00023 #include <assert.h> 00024 00025 #include <pelib/sort.h> 00026 00027 static int 00028 swap(array_t(int)* array, int left, int right) 00029 { 00030 int pivot; 00031 pivot = pelib_array_read(int)(array, left); 00032 pelib_array_write(int)(array, left, pelib_array_read(int)(array, right)); 00033 pelib_array_write(int)(array, right, pivot); 00034 00035 return 0; 00036 } 00037 00038 struct qsort_param 00039 { 00040 array_t 00041 (int) 00042 *array; 00043 qsort_tune_t tune; 00044 }; 00045 typedef struct qsort_param qsort_param_t; 00046 00047 struct qsort_next_step 00048 { 00049 char done; 00050 qsort_param_t left, right; 00051 }; 00052 typedef struct qsort_next_step qsort_next_step_t; 00053 00054 struct qsort_bound 00055 { 00056 int begin, end; 00057 }; 00058 typedef struct qsort_bound qsort_bound_t; 00059 00060 // Generate stack for qsort_param_t structure 00061 #define STRUCT_T qsort_bound_t 00062 #include <pelib/structure.h> 00063 00064 #define STACK_T qsort_bound_t 00065 #include <pelib/stack.h> 00066 00067 #define STACK_T qsort_bound_t 00068 #include <pelib/stack.c> 00069 00070 int 00071 pelib_copy 00072 ( qsort_bound_t)(qsort_bound_t s, qsort_bound_t *d) 00073 { 00074 d->begin = s.begin; 00075 d->end = s.end; 00076 00077 return 1; 00078 } 00079 int 00080 pelib_init 00081 ( qsort_bound_t)(qsort_bound_t *d) 00082 { 00083 d->begin = 0; 00084 d->end = 0; 00085 00086 return 1; 00087 } 00088 00089 static void 00090 move(array_t(int)* array, int pos, int dest) 00091 { 00092 int pivot; 00093 int i; 00094 00095 assert(pos >= dest); 00096 00097 pivot = pelib_array_read(int)(array, pos); 00098 for (i = pos; i > dest; i--) 00099 { 00100 pelib_array_write(int)(array, i, pelib_array_read(int)(array, i - 1)); 00101 } 00102 pelib_array_write(int)(array, dest, pivot); 00103 } 00104 00105 void 00106 pelib_insertsort_window(array_t(int)* array, int start, int stop) 00107 { 00108 int i, j; 00109 00110 assert(stop >= start); 00111 00112 i = 0; 00113 j = 0; 00114 00115 for (i = start + 1; i < stop; i++) 00116 { 00117 j = i; 00118 while (pelib_compare(int)(pelib_array_read(int)(array, i), 00119 pelib_array_read(int)(array, j - 1)) < 0 && j > start) 00120 { 00121 j--; 00122 } 00123 move(array, i, j); 00124 } 00125 } 00126 00127 void 00128 pelib_insertsort(array_t(int)* array) 00129 { 00130 pelib_insertsort_window(array, 0, pelib_array_length(int)(array)); 00131 } 00132 00133 int 00134 pelib_sample(array_t(int)* array, int ratio, int start, int stop) 00135 { 00136 double pivot; 00137 int i; 00138 int read; 00139 00140 // Sample input to find a good pivot 00141 pivot = 0; 00142 if (stop - start >= ratio) 00143 { 00144 array_t(int)* sample = pelib_alloc_collection(array_t(int))(ratio); 00145 for (i = start; i < stop; i += (int)((float) (stop - start) / ratio)) 00146 { 00147 read = pelib_array_read(int)(array, (int)i); 00148 pelib_array_append(int)(sample, read); 00149 } 00150 00151 for (i = 0; i < pelib_array_length(int)(sample); i++) 00152 { 00153 pivot += (double) pelib_array_read(int)(sample, i); 00154 } 00155 pivot /= (double) pelib_array_length(int)(sample); 00156 pelib_free(array_t(int))(sample); 00157 } 00158 else 00159 { 00160 pivot = 0; 00161 for (i = start; i < stop; i++) 00162 { 00163 pivot += (double) pelib_array_read(int)(array, i); 00164 00165 } 00166 pivot /= (double) (stop - start); 00167 } 00168 00169 return (int) pivot; 00170 } 00171 00172 static qsort_next_step_t 00173 quicksort_tune(qsort_param_t param) 00174 { 00175 qsort_next_step_t next; 00176 int i, j; 00177 00178 #if 0 00179 if((param.tune.end > 16777216 && param.tune.begin < 16777216 && param.tune.end - param.tune.begin < param.tune.threshold) || param.tune.begin == 0 && param.tune.end == 100000000) 00180 { 00181 char s[30]; 00182 struct tm tim; 00183 time_t now; 00184 00185 now = time(NULL); 00186 tim = *(localtime(&now)); 00187 strftime(s,30,"%b %d, %Y; %H:%M:%S",&tim); 00188 printf("[%s, %s] %d->%d\n", s, __FUNCTION__, param.tune.begin, param.tune.end); 00189 } 00190 #endif 00191 00192 if (param.tune.end - param.tune.begin > param.tune.threshold) // Threshold to be decided experimentally 00193 { 00194 int pivot, pv; 00195 pivot = pelib_sample(param.array, param.tune.num_sample, 00196 param.tune.begin, param.tune.end); 00197 00198 next.done = 0; 00199 next.left = param; 00200 next.right = param; 00201 00202 i = param.tune.begin; 00203 j = param.tune.end; 00204 pv = j; 00205 00206 int read; 00207 00208 while (i < j) 00209 { 00210 read = pelib_array_read(int)(param.array, i); 00211 if (read < pivot) 00212 { 00213 i++; 00214 } 00215 else 00216 { 00217 // Alloc a j 00218 j--; 00219 swap(param.array, i, j); 00220 00221 if (pelib_array_read(int)(param.array, j) == pivot) 00222 { 00223 // Alloc a pv 00224 pv--; 00225 swap(param.array, j, pv); 00226 } 00227 } 00228 } 00229 next.left.tune.end = i; 00230 00231 for (i = pv; i < param.tune.end; i++) 00232 { 00233 swap(param.array, j, pv); 00234 j++; 00235 pv++; 00236 } 00237 00238 next.right.tune.begin = j; 00239 return next; 00240 } 00241 else 00242 { 00243 pelib_insertsort_window(param.array, param.tune.begin, param.tune.end); 00244 00245 next.done = 1; 00246 00247 return next; 00248 } 00249 } 00250 00251 static qsort_next_step_t 00252 quicksort_tune_recursive(qsort_param_t param) 00253 { 00254 qsort_next_step_t next; 00255 int i, j; 00256 00257 #if 0 00258 if((param.tune.end > 16777216 && param.tune.begin < 16777216 && param.tune.end - param.tune.begin < param.tune.threshold) || param.tune.begin == 0 && param.tune.end == 100000000) 00259 { 00260 char s[30]; 00261 struct tm tim; 00262 time_t now; 00263 00264 now = time(NULL); 00265 tim = *(localtime(&now)); 00266 strftime(s,30,"%b %d, %Y; %H:%M:%S",&tim); 00267 printf("[%s, %s] %d->%d\n", s, __FUNCTION__, param.tune.begin, param.tune.end); 00268 } 00269 #endif 00270 00271 if (param.tune.end - param.tune.begin > param.tune.threshold) // Threshold to be decided experimentally 00272 { 00273 int pivot, pv; 00274 pivot = pelib_sample(param.array, param.tune.num_sample, 00275 param.tune.begin, param.tune.end); 00276 00277 next.done = 0; 00278 next.left = param; 00279 next.right = param; 00280 00281 i = param.tune.begin; 00282 j = param.tune.end; 00283 pv = j; 00284 00285 while (i < j) 00286 { 00287 if (pelib_array_read(int)(param.array, i) < pivot) 00288 { 00289 i++; 00290 } 00291 else 00292 { 00293 // Alloc a j 00294 j--; 00295 swap(param.array, i, j); 00296 00297 if (pelib_array_read(int)(param.array, j) == pivot) 00298 { 00299 // Alloc a pv 00300 pv--; 00301 swap(param.array, j, pv); 00302 } 00303 } 00304 } 00305 next.left.tune.end = i; 00306 00307 for (i = pv; i < param.tune.end; i++) 00308 { 00309 swap(param.array, j, pv); 00310 j++; 00311 pv++; 00312 } 00313 00314 next.right.tune.begin = j; 00315 00316 quicksort_tune_recursive(next.left); 00317 quicksort_tune_recursive(next.right); 00318 next.done = 1; 00319 00320 return next; 00321 } 00322 else 00323 { 00324 pelib_insertsort_window(param.array, param.tune.begin, param.tune.end); 00325 00326 next.done = 1; 00327 00328 return next; 00329 } 00330 } 00331 00332 void 00333 pelib_quicksort_tune(array_t(int)* array, qsort_tune_t p) 00334 { 00335 qsort_next_step_t res; 00336 qsort_param_t param; 00337 qsort_bound_t start; 00338 stack_t(qsort_bound_t) * stack; 00339 00340 stack = pelib_alloc_collection(stack_t(qsort_bound_t))(0); 00341 pelib_init(stack_t(qsort_bound_t))(stack); 00342 00343 param.array = array; 00344 param.tune = p; 00345 00346 start.begin = p.begin; 00347 start.end = p.end; 00348 pelib_stack_push(qsort_bound_t)(stack, start); 00349 00350 res.done = 1; 00351 while (res.done == 0 || !pelib_stack_isempty(qsort_bound_t)(stack)) 00352 { 00353 if (res.done == 1) 00354 { 00355 int ret = pelib_stack_pop(qsort_bound_t)(stack, &start); 00356 param.tune.begin = start.begin; 00357 param.tune.end = start.end; 00358 00359 res = quicksort_tune(param); 00360 } 00361 else 00362 { 00363 start.begin = res.right.tune.begin; 00364 start.end = res.right.tune.end; 00365 pelib_stack_push(qsort_bound_t)(stack, start); 00366 00367 start.begin = res.left.tune.begin; 00368 start.end = res.left.tune.end; 00369 pelib_stack_push(qsort_bound_t)(stack, start); 00370 00371 res.done = 1; 00372 } 00373 } 00374 00375 pelib_free(stack_t(qsort_bound_t))(stack); 00376 } 00377 00378 void 00379 pelib_quicksort_tune_recursive(array_t(int)* array, qsort_tune_t p) 00380 { 00381 qsort_param_t param; 00382 00383 param.array = array; 00384 param.tune = p; 00385 00386 quicksort_tune_recursive(param); 00387 } 00388 00389 void 00390 pelib_quicksort_window(array_t(int)* array, int start, int stop) 00391 { 00392 qsort_tune_t p; 00393 00394 p.begin = start; 00395 p.end = stop; 00396 p.threshold = PELIB_QUICKSORT_THRESHOLD; 00397 p.num_sample = PELIB_QUICKSORT_NUM_SAMPLE; 00398 00399 pelib_quicksort_tune(array, p); 00400 } 00401 00402 void 00403 pelib_quicksort(array_t(int)* array) 00404 { 00405 qsort_tune_t p; 00406 00407 p.begin = 0; 00408 p.end = pelib_array_length(int)(array); 00409 p.threshold = PELIB_QUICKSORT_THRESHOLD; 00410 p.num_sample = PELIB_QUICKSORT_NUM_SAMPLE; 00411 00412 pelib_quicksort_tune(array, p); 00413 } 00414 00415 int 00416 pelib_mergesort(array_t(int)* array) 00417 { 00418 if(pelib_array_length(int)(array) <= 1) 00419 { 00420 return 1; 00421 } 00422 else 00423 { 00424 return pelib_array_length(int)(array) / 2; 00425 // left = pelib_alloc_from( 00426 } 00427 } 00428 00429 00430 int 00431 pelib_is_increasing(array_t(int)* array) 00432 { 00433 int val, ref; 00434 int i, res; 00435 res = 1; 00436 00437 if (pelib_array_length(int)(array) > 0) 00438 { 00439 val = pelib_array_read(int)(array, 0); 00440 for (i = 1; i < pelib_array_length(int)(array); i++) 00441 { 00442 ref = pelib_array_read(int)(array, i); 00443 res = res && (pelib_compare(int)(val, ref) <= 0); 00444 val = ref; 00445 } 00446 00447 return res; 00448 } 00449 else 00450 { 00451 return 1; 00452 } 00453 }