///////////////////////////////////////////////////////////////////////////// // Name: medsort.h // Purpose: Macros of generic public domain median sorting algorithms // Author: John Labenski & mostly others // Created: 07/01/02 // Copyright: see macro headers, rewritten by John Labenski, 2002 // License: Public Domain ///////////////////////////////////////////////////////////////////////////// #ifndef __WX_MEDSORT_H__ #define __WX_MEDSORT_H__ /* Notes : code taken from http://ndevilla.free.fr/median/ see the headers for each function taken from the files see bottom for benchmark data Each of these functions are implemented as macros that can be used to either DECLARE and DEFINE functions for the different element types required or they can be used inline for example: in a header file declare the function with DECLARE_WIRTHS_MEDIAN( wirths_median_int, int ) and you'll get this code int wirths_median_int( int *arr, int n, int &median ); in the c(pp) file define the function DEFINE_WIRTHS_MEDIAN( wirths_median_int, int ) and get int withs_median_int( int *arr, int n, int &median ) { the function itself } otherwise use the macro inline in some other function IMPLEMENT_WIRTHS_MEDIAN(int, arr, n, &median) */ /*--------------------------------------------------------------------------- * This Quickselect routine is based on the algorithm described in * "Numerical recipes in C", Second Edition, * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 * This code by Nicolas Devillard - 1998. Public domain. ---------------------------------------------------------------------------- This does NOT fully sort the input array, but it does modify it QUICK_SELECT(elem_type, arr, n, median) elem_type is a valid data type, int, long, unsigned char, float... arr is an array delcared as elem_type *array and passed as array n is the size of the array, ie. total element count median contains the median value on exit ---------------------------------------------------------------------------*/ #define DECLARE_QUICK_SELECT( name, elem_type ) \ elem_type name( elem_type *arr, int n, elem_type &median ); #define DEFINE_QUICK_SELECT( name, elem_type ) \ elem_type name( elem_type *arr, int n, elem_type &median ) \ IMPLEMENT_QUICK_SELECT( elem_type, arr, n, median ) #define IMPLEMENT_QUICK_SELECT(elem_type, arr, n, median) \ { \ int low=0, high=n-1, half=(low+high)/2, middle, ll, hh; \ \ for (;;) { \ if (high <= low) /* One element only */ \ break; /*return arr[half] ; */ \ \ if (high == low + 1) { /* Two elements only */ \ if (arr[low] > arr[high]) \ { register elem_type t=arr[low];arr[low]=arr[high];arr[high]=t; } \ break; /* return arr[half] ; */ \ } \ \ /* Find median of low, middle and high items; swap into low */ \ middle = (low + high) / 2; \ if (arr[middle] > arr[high]) { register elem_type t=arr[middle];arr[middle]=arr[high];arr[high]=t; } \ if (arr[low] > arr[high]) { register elem_type t=arr[low]; arr[low] =arr[high];arr[high]=t; } \ if (arr[middle] > arr[low] ) { register elem_type t=arr[middle];arr[middle]=arr[low]; arr[low] =t; } \ \ /* Swap low item (now in position middle) into position (low+1) */ \ { register elem_type t=arr[middle];arr[middle]=arr[low+1];arr[low+1]=t; } \ \ /* Nibble from ends towards middle, swapping items when stuck */ \ ll = low + 1; \ hh = high; \ for (;;) { \ do ll++; while (arr[low] > arr[ll] ); \ do hh--; while (arr[hh] > arr[low]); \ \ if (hh < ll) break; \ \ { register elem_type t=arr[ll];arr[ll]=arr[hh];arr[hh]=t;} \ } \ \ /* Swap middle item (in position low) back into correct position */ \ { register elem_type t=arr[low];arr[low]=arr[hh];arr[hh]=t; } \ \ /* Re-set active partition */ \ if (hh <= half) low = ll; \ if (hh >= half) high = hh - 1; \ } \ median = arr[half]; \ } /*--------------------------------------------------------------------------- Function : kth_smallest() In : array of elements, # of elements in the array, rank k Out : one element Job : find the kth smallest element in the array Notice : use the median() macro defined below to get the median. Reference: Author: Wirth, Niklaus Title: Algorithms + data structures = programs Publisher: Englewood Cliffs: Prentice-Hall, 1976 Physical description: 366 p. Series: Prentice-Hall Series in Automatic Computation --------------------------------------------------------------------------- This does NOT fully sort the input array, but it does modify it WIRTHS_KTH_SMALLEST(elem_type, arr, n, k, ksmallest) elem_type is a valid data type, int, long, unsigned char, float... arr is an array delcared as elem_type *array and passed as array n is the size of the array, ie. total element count k is the kth smallest value of the array that you want to find ksmallest contains the kth smallest value of arr on exit WIRTHS_MEDIAN(elem_type, arr, n, median) finds median value Calls WIRTHS_KTH_SMALLEST with (k = n/2) fills median ---------------------------------------------------------------------------*/ #define DECLARE_WIRTHS_MEDIAN( name, elem_type ) \ elem_type name( elem_type *arr, int n, elem_type &median ); #define DEFINE_WIRTHS_MEDIAN( name, elem_type ) \ elem_type name( elem_type *arr, int n, elem_type &median ) \ WIRTHS_MEDIAN( elem_type, arr, n, median ) #define IMPLEMENT_WIRTHS_MEDIAN(elem_type, arr, n, median) \ IMPLEMENT_WIRTHS_KTH_SMALLEST(elem_type, arr, n, (((n)&1)?((n)/2):(((n)/2)-1)), median) #define DECLARE_WIRTHS_KTH_SMALLEST( name, elem_type ) \ elem_type name( elem_type *arr, int n, elem_type &median ); #define DEFINE_WIRTHS_KTH_SMALLEST( name, elem_type ) \ elem_type name( elem_type *arr, int n, elem_type &median ) \ IMPLEMENT_WIRTHS_MEDIAN( elem_type, arr, n, median ) #define IMPLEMENT_WIRTHS_KTH_SMALLEST(elem_type, arr, n, k, ksmallest) \ { \ register int i, j, l=0, m=n-1; \ register elem_type x; \ \ while (lmax) max=arr[i]; \ } \ \ while (1) { \ guess = (min+max)/2; \ less = 0; greater = 0; equal = 0; \ maxltguess = min; \ mingtguess = max; \ for (i=0; imaxltguess) maxltguess = arr[i]; \ } else if (arr[i]>guess) { \ greater++; \ if (arr[i]greater) max = maxltguess; \ else min = mingtguess; \ } \ if (less >= (n+1)/2) median = maxltguess; \ else if (less+equal >= (n+1)/2) median = guess; \ else median = mingtguess; \ } /*---------------------------------------------------------------------------- Function : pixel_qsort() In : pixel array, size of the array Out : void Job : sort out the array of pixels Notice : optimized implementation, unreadable. --------------------------------------------------------------------------- This fully sorts the input array by modifying it DECLARE_PIXEL_QSORT(name, elem_type) ----------------------------------------------------------------------------*/ #define PIXEL_QSORT_STACK_SIZE 50 #define PIXEL_QSORT_THRESHOLD 7 #define DECLARE_PIXEL_QSORT( name, elem_type ) \ void name( elem_type *arr, int n ); #define DEFINE_PIXEL_QSORT( name, elem_type ) \ void name( elem_type *arr, int n ) \ IMPLEMENT_PIXEL_QSORT( name, elem_type ) #define IMPLEMENT_PIXEL_QSORT( elem_type, arr, n ) \ { \ int i, ir=n, j, k, l=1, j_stack=0; \ int *i_stack ; \ elem_type a ; \ \ i_stack = (int*)malloc(PIXEL_QSORT_STACK_SIZE * sizeof(elem_type)); \ for (;;) { \ if (ir-l < PIXEL_QSORT_THRESHOLD) { \ for (j=l+1 ; j<=ir ; j++) { \ a = arr[j-1]; \ for (i=j-1 ; i>=1 ; i--) { \ if (arr[i-1] <= a) break; \ arr[i] = arr[i-1]; \ } \ arr[i] = a; \ } \ if (j_stack == 0) break; \ ir = i_stack[j_stack-- -1]; \ l = i_stack[j_stack-- -1]; \ } else { \ k = (l+ir) >> 1; \ { elem_type t=arr[k-1];arr[k-1]=arr[l];arr[l]=t; } \ if (arr[l] > arr[ir-1]) { \ { elem_type t=arr[l];arr[l]=arr[ir-1];arr[ir-1]=t; } \ } \ if (arr[l-1] > arr[ir-1]) { \ { elem_type t=arr[l-1];arr[l-1]=arr[ir-1];arr[ir-1]=t; } \ } \ if (arr[l] > arr[l-1]) { \ { elem_type t=arr[l];arr[l]=arr[l-1];arr[l-1]=t; } \ } \ i = l+1; j = ir; a = arr[l-1]; \ for (;;) { \ do i++; while (arr[i-1] < a); \ do j--; while (arr[j-1] > a); \ if (j < i) break; \ { elem_type t=arr[i-1];arr[i-1]=arr[j-1];arr[j-1]=t; } \ } \ arr[l-1] = arr[j-1]; \ arr[j-1] = a; \ j_stack += 2; \ wxASSERT(!(j_stack>PIXEL_QSORT_STACK_SIZE)); \ /* if (j_stack > PIXEL_QSORT_STACK_SIZE) { */ \ /* printf("stack too small in pixel_qsort: aborting"); */ \ /* exit(-2001); } */ \ if (ir-i+1 >= j-l) { \ i_stack[j_stack-1] = ir; \ i_stack[j_stack-2] = i; \ ir = j-1; \ } else { \ i_stack[j_stack-1] = j-1; \ i_stack[j_stack-2] = l; \ l = i; \ } \ } \ } \ free(i_stack); \ } /*------------------------------------------------------------------------- Function : pixel_qsort2() In : two pixel arrays, size of the arrays Out : void Job : sort out both arrays based on the first array Notice : optimized implementation, unreadable. --------------------------------------------------------------------------- This fully sorts the input arrays by modifying them Uses the first array as the comparison array DECLARE_PIXEL_QSORT2(name, elem_type) ----------------------------------------------------------------------------*/ #define PIXEL_QSORT2_STACK_SIZE 50 #define PIXEL_QSORT2_THRESHOLD 7 #define DECLARE_PIXEL_QSORT2( name, elem_type ) \ void name( elem_type *arr, elem_type *arr2, int n ); #define DEFINE_PIXEL_QSORT2( name, elem_type ) \ void name( elem_type *arr, elem_type *arr2, int n ) \ IMPLEMENT_PIXEL_QSORT2( name, elem_type ) #define IMPLEMENT_PIXEL_QSORT2( elem_type, arr, arr2, n ) \ { \ int i, ir=n, j, k, l=1, j_stack=0; \ int *i_stack ; \ elem_type a, a2 ; \ \ i_stack = (int*)malloc(PIXEL_QSORT2_STACK_SIZE * sizeof(elem_type)); \ for (;;) { \ if (ir-l < PIXEL_QSORT2_THRESHOLD) { \ for (j=l+1 ; j<=ir ; j++) { \ a = arr[j-1]; a2 = arr2[j-1]; \ for (i=j-1 ; i>=1 ; i--) { \ if (arr[i-1] <= a) break; \ arr[i] = arr[i-1]; \ arr2[i] = arr2[i-1]; \ } \ arr[i] = a; arr2[i] = a2; \ } \ if (j_stack == 0) break; \ ir = i_stack[j_stack-- -1]; \ l = i_stack[j_stack-- -1]; \ } else { \ k = (l+ir) >> 1; \ { elem_type t=arr[k-1];arr[k-1]=arr[l];arr[l]=t; t=arr2[k-1];arr2[k-1]=arr2[l];arr2[l]=t; } \ if (arr[l] > arr[ir-1]) { \ { elem_type t=arr[l];arr[l]=arr[ir-1];arr[ir-1]=t; t=arr2[l];arr2[l]=arr2[ir-1];arr2[ir-1]=t;} \ } \ if (arr[l-1] > arr[ir-1]) { \ { elem_type t=arr[l-1];arr[l-1]=arr[ir-1];arr[ir-1]=t; t=arr2[l-1];arr2[l-1]=arr2[ir-1];arr2[ir-1]=t;} \ } \ if (arr[l] > arr[l-1]) { \ { elem_type t=arr[l];arr[l]=arr[l-1];arr[l-1]=t; t=arr2[l];arr2[l]=arr2[l-1];arr2[l-1]=t; } \ } \ i = l+1; j = ir; a = arr[l-1]; a2 = arr2[l-1]; \ for (;;) { \ do i++; while (arr[i-1] < a); \ do j--; while (arr[j-1] > a); \ if (j < i) break; \ { elem_type t=arr[i-1];arr[i-1]=arr[j-1];arr[j-1]=t; t=arr2[i-1];arr2[i-1]=arr2[j-1];arr2[j-1]=t;} \ } \ arr[l-1] = arr[j-1]; arr2[l-1] = arr2[j-1]; \ arr[j-1] = a; arr2[j-1] = a2; \ j_stack += 2; \ wxASSERT(!(j_stack>PIXEL_QSORT_STACK_SIZE)); \ /* if (j_stack > PIXEL_QSORT_STACK_SIZE) { */ \ /* printf("stack too small in pixel_qsort: aborting"); */ \ /* exit(-2001); } */ \ if (ir-i+1 >= j-l) { \ i_stack[j_stack-1] = ir; \ i_stack[j_stack-2] = i; \ ir = j-1; \ } else { \ i_stack[j_stack-1] = j-1; \ i_stack[j_stack-2] = l; \ l = i; \ } \ } \ } \ free(i_stack); \ } /* Abbreviated benchmark data from http://ndevilla.free.fr/median/median/node13.html (QuickSelect, Wirth, Aho/Hopcroft/Ullman, Torben, pixel quicksort) Pentium II 400 MHz running Linux 2.0 with glibc-2.0.7. The basic method using the libc qsort() function has not been represented here, because it is so slow compared to the others that it would make the plot unreadable. Furthermore, it depends on the local implementation of your C library. Ratios have been obtained for sets with increasing number of values, from 1e4 to 1e6. The speed ratios have been computed to the fastest method on average (QuickSelect), then averaged over all measure points. QuickSelect : 1.00 WIRTH median : 1.33 AHU median : 3.71 Torben : 8.95 fast pixel sort : 6.50 Elm Qselect Wirth AHU Torben pqsort 10000 0.000 0.000 0.010 0.010 0.010 100000 0.010 0.020 0.050 0.140 0.100 200000 0.040 0.040 0.180 0.310 0.220 300000 0.070 0.060 0.190 0.470 0.340 400000 0.080 0.140 0.150 0.630 0.450 500000 0.110 0.080 0.510 0.800 0.580 600000 0.090 0.140 0.320 0.940 0.730 700000 0.120 0.100 0.450 1.100 0.810 800000 0.120 0.160 0.590 1.270 0.940 900000 0.180 0.250 0.760 1.430 1.070 1000000 0.210 0.290 0.600 1.580 1.240 */ #endif //__WX_MEDSORT_H__