// utf-8

/*	Threshold Sorter (median value variant)		adaptable via #defines
	---------------------------------------		----------------------

	Copyright  (c)	Günter Woigk   1998
  					mailto:kio@little-bat.de

	This file is free software

 	This program is distributed in the hope that it will be useful,
 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

 	Permission to use, copy, modify, distribute, and sell this software and
 	its documentation for any purpose is hereby granted without fee, provided
 	that the above copyright notice appear in all copies and that both that
 	copyright notice and this permission notice appear in supporting
 	documentation, and that the name of the copyright holder not be used
 	in advertising or publicity pertaining to distribution of the software
 	without specific, written prior permission. The copyright holder makes no
 	representations about the suitability of this software for any purpose.
 	It is provided "as is" without express or implied warranty.

 	THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 	INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 	EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 	CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 	DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 	TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 	PERFORMANCE OF THIS SOFTWARE.


<German>
	Ein Bereich wird sortiert, indem geschätzt wird, welcher Wert etwa die Mitte bilden
	wird, und dann alle Einträge, die unterhalb dieses Schwellwertes liegen, nach unten und 
	alle Einträge, die darüber liegen, nach oben getauscht werden. Danach liegen zwei, 
	möglicherweise deutlich ungleich große Bereiche vor, von denen der eine nur Einträge
	enthält, die unterhalb dieser Schwelle liegen und der andere nur Einträge, die oberhalb
	dieser Schwelle liegen. Danach werden diese beiden Bereiche rekursiv sortiert.

	Zur Bestimmung des Schwellwertes wird im einfachsten Fall das arithmetische Mittel
	zwischen Maximal- und Minimalwert der Einträge benutzt. Dazu muß zuerst der Maximal- 
	und Minimalwert gesucht werden.


	Vorteile:
		nicht quadratischer Zeitzuwachs
		benötigt keinen temp array

	Nachteil:
		das Macro WERT() muß implementierbar sein und einen Datentyp ergeben,
			mit dem min+(max-min)/2 berechenbar ist und
			für den der Operator ">"  definiert ist
		Die Reihenfolge von Elementen mit gleichem WERT wird verwürfelt
			also evtl. ungeeignet für's Sortieren von Datenbanken nach 2 oder mehr Spalten

	Sonstiges:
		Vorsortierte Arrays werden etwas schneller sortiert
		Felder mit sehr ungleich verteiltem Inhalt werden langsamer sortiert
</German>


	Macros:	
	-------

		Name		Meaning								Default value	
		----------	----------------------------------	-------------
		TYPE		Type of data						int				
		CTYP		Type of compare value				TYPE
		WERT(N)		Macro to calculate compare value	N
		SWAP(A,B)	Macro to swap two dates				Z=A,A=B,B=Z
		SORTER		Name of sorter function				Sort

		

	Examples:
	---------

	1.	A sorter for ints:

			#include	"sort.cp"


	2.	A sorter for floats:

			#define		TYPE				float
			#include	"sort.cp"

	3.	A sorter for c-type strings:
		(first 4 characters only)
		 
			#define		TYPE				char*
			#define		CTYP				long
			#define		WERT(N)				*(long*)N		// PowerPC, m68k 
			#include	"sort.cp"
			
	4.	A sorter for a struct or class:

			struct { int von,nach,wert; } 	Zug;
			#define		TYPE				Zug
			#define		CTYP				int
			#define		WERT(N)				N->wert
			#include	"sort.cp"
*/



/******	default settings ***********************************
*/
#ifndef TYPE
#define	TYPE		int			// type of values to sort
#endif

#ifndef CTYP
#define	CTYP		TYPE		// type of compare value
#endif

#ifndef WERT
#define	WERT(N)		N			// function for calculating the compare value
#endif

#ifndef SWAP
#define	SWAP(A,B)	Z=A,A=B,B=Z	// function to swap two items
#endif

#ifndef SORTER
#define SORTER		Sort
#endif



/****** the sorter ****************************************
*/
void SORTER ( TYPE* array, int count )
{
// nothing to do ?
	if (count<=1) return;

// local vars
	CTYP min,m,max;
	TYPE *a,*a0,*e,*e0,*p,z;

// define stack
// for arrays with up to 2^32 elements
	const int stacksize = 32;		
	struct
	{	TYPE	*a;
		TYPE	*e;
		CTYP	min;
		CTYP	max;
	}
	stack[stacksize], *sp;

// bestimme a, e, min und max für ersten subbereich ( == array )
	a=e=array;
	min=max=WERT(array);

	for ( p=array+count-1; p>array; p-- )
	{	m = WERT(p);
		if (min>m) { a=p; min=m; } else if (m>max) { e=p; max=m; }
	}

// auslaufschutz errichten
	p=array; 
	SWAP(*p,*a); a=p+1;
	p=array+count-1;
	SWAP(*p,*e); e=p-1;

// nothing more to do ?
	if (count<=3) return;

// init stack
	sp = stack;
//	sp->min=min;
//	sp->max=max;
//	sp->a=a;
//	sp->e=e;


// ---- do it ! ----
loop:
	if (e>a+2)
	{
// 4 oder mehr Elemenete  =>  in zwei Subbereiche teilen
		if (min==max) goto x;  	// sehr viele gleiche Elemente !!!
		m = min+(max-min)/2; 	// (min+max)/2  rundet immer zur 0 !!!
		a0=a; e0=e;
  loo:	while (m>WERT(a)) a++;
		while (WERT(e)>m) e--;
		if (a<e) { SWAP(*a,*e);a++;e--; goto loo; }
		// [a0..e]  und  [a..e0]  mit [min..m] bzw. m]..max]
		// die Subranges können leer sein!!!

	// den größeren subbereich auf den stack
	// und den kleineren sofort sortieren
		if ( e - a0 > e0 - a )
		{
	// vorne>hinten  =>  vorne auf den stack, hinten beibehalten
			sp->max = m;
			sp->min = min;
			sp->a=a0;
			sp->e=e;
			sp++;
			a=a;
			e=e0;
			min=m+1;
			max=max;
			goto loop;
		}
		else
		{
	// vorne<hinten  =>  hinten auf den stack, vorne beibehalten
			sp->max = max;
			sp->min = m+1;
			sp->a = a;
			sp->e = e0;
			sp++;
			a=a0;
			e=e;
			min=min;
			max=m;
			goto loop;
		}
	}

// 0, 1, 2 oder 3 elemente direkt sortieren
	if (e>a)
	{	// 2 oder 3 elemente
		if (WERT(a)>WERT(e)) SWAP(*a,*e);
		if (e==a+2)
		{	// 3 elemente
			p=a+1;
			if (WERT(a)>WERT(p)) SWAP(*a,*p); else
			if (WERT(p)>WERT(e)) SWAP(*e,*p);
		}
	}

// get next subrange from stack
x:	if (--sp<stack) return;	// no subrange left  =>  ready!
	a	= sp->a;
	e	= sp->e;
	min	= sp->min;
	max	= sp->max;
	goto loop;
}


#undef	TYPE
#undef	CTYP
#undef	WERT
#undef	SWAP
#undef	SORTER
















