446 lines
24 KiB
Text
446 lines
24 KiB
Text
/////////////////////////////////////////////////////////////////////////////
|
|
// 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 (l<m) { \
|
|
x=arr[k]; i=l; j=m; \
|
|
do { \
|
|
while (arr[i]<x) i++; \
|
|
while (x<arr[j]) j--; \
|
|
if (i<=j) { \
|
|
{ register elem_type t=arr[i]; \
|
|
arr[i]=arr[j]; arr[j]=t; } \
|
|
i++; j--; } \
|
|
} while (i<=j); \
|
|
if (j<k) l=i; \
|
|
if (k<i) m=j; \
|
|
} \
|
|
ksmallest = arr[k]; \
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* The following code is public domain.
|
|
* Algorithm by Torben Mogensen, implementation by N. Devillard.
|
|
* This code in public domain.
|
|
---------------------------------------------------------------------------
|
|
|
|
This does NOT modify NOR sort the input array
|
|
|
|
TORBEN_MEDIAN(elem_type, arr, n )
|
|
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
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
#define DECLARE_TORBEN_MEDIAN( name, elem_type ) \
|
|
elem_type name( elem_type *arr, int n, elem_type &median );
|
|
|
|
#define DEFINE_TORBEN_MEDIAN( name, elem_type ) \
|
|
elem_type name( elem_type *arr, int n, elem_type &median ) \
|
|
IMPLEMENT_TORBEN_MEDIAN( elem_type, arr, n, median )
|
|
|
|
#define IMPLEMENT_TORBEN_MEDIAN( elem_type, arr, n ) \
|
|
{ \
|
|
int i, less, greater, equal; \
|
|
elem_type min, max, guess, maxltguess, mingtguess; \
|
|
\
|
|
min = max = arr[0]; \
|
|
for (i=1; i<n; i++) { \
|
|
if (arr[i]<min) min=arr[i]; \
|
|
if (arr[i]>max) max=arr[i]; \
|
|
} \
|
|
\
|
|
while (1) { \
|
|
guess = (min+max)/2; \
|
|
less = 0; greater = 0; equal = 0; \
|
|
maxltguess = min; \
|
|
mingtguess = max; \
|
|
for (i=0; i<n; i++) { \
|
|
if (arr[i]<guess) { \
|
|
less++; \
|
|
if (arr[i]>maxltguess) maxltguess = arr[i]; \
|
|
} else if (arr[i]>guess) { \
|
|
greater++; \
|
|
if (arr[i]<mingtguess) mingtguess = arr[i]; \
|
|
} else equal++; \
|
|
} \
|
|
if (less <= (n+1)/2 && greater <= (n+1)/2) break; \
|
|
else if (less>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__
|