2008-02-26 14:55:23 +01:00
/*
LA : linear algebra C + + interface library
Copyright ( C ) 2008 Jiri Pittner < jiri . pittner @ jh - inst . cas . cz > or < jiri @ pittnerovi . com >
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
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 . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2005-09-11 22:04:24 +02:00
# ifndef _QSORT_H
# define _QSORT_H
2006-04-01 16:56:35 +02:00
//quicksort, returns parity of the permutation
2009-11-12 22:01:19 +01:00
//
namespace LA {
2005-09-06 17:55:07 +02:00
template < typename INDEX , typename COMPAR >
int genqsort ( INDEX l , INDEX r , COMPAR ( * cmp ) ( const INDEX , const INDEX ) , void ( * swap ) ( const INDEX , const INDEX ) )
{
INDEX i , j , piv ;
int parity = 0 ;
if ( r < = l ) return parity ; //1 element
if ( cmp ( r , l ) < 0 ) { parity ^ = 1 ; swap ( l , r ) ; }
if ( r - l = = 1 ) return parity ; //2 elements and preparation for median
2006-04-01 16:56:35 +02:00
piv = l + ( r - l ) / 2 ; //pivoting by median of 3 - safer
2005-09-06 17:55:07 +02:00
if ( cmp ( piv , l ) < 0 ) { parity ^ = 1 ; swap ( l , piv ) ; } //and change the pivot element implicitly
if ( cmp ( r , piv ) < 0 ) { parity ^ = 1 ; swap ( r , piv ) ; } //and change the pivot element implicitly
if ( r - l = = 2 ) return parity ; //in the case of 3 elements we are finished too
//general case , l-th r-th already processed
i = l + 1 ; j = r - 1 ;
do {
//important sharp inequality - stops at sentinel element for efficiency
// this is inefficient if all keys are equal - unnecessary n log n swaps are done, but we assume that it is atypical input
while ( cmp ( i + + , piv ) < 0 ) ;
i - - ;
while ( cmp ( j - - , piv ) > 0 ) ;
j + + ;
if ( i < j )
{
// swap and keep track of position of pivoting element
parity ^ = 1 ; swap ( i , j ) ;
if ( i = = piv ) piv = j ; else if ( j = = piv ) piv = i ;
}
if ( i < = j ) { i + + ; j - - ; }
} while ( i < = j ) ;
if ( j - l < r - i ) //because of the stack in bad case process first the shorter subarray
{ if ( l < j ) parity ^ = genqsort ( l , j , cmp , swap ) ; if ( i < r ) parity ^ = genqsort ( i , r , cmp , swap ) ; }
else
{ if ( i < r ) parity ^ = genqsort ( i , r , cmp , swap ) ; if ( l < j ) parity ^ = genqsort ( l , j , cmp , swap ) ; }
return parity ;
}
2005-09-11 22:04:24 +02:00
2006-04-01 06:48:01 +02:00
2006-04-01 16:56:35 +02:00
2006-04-01 14:58:57 +02:00
//for SORTABLE classes which provide LA_sort_traits<SORTABLE,INDEX,type>::compare and swap member functions
2006-04-01 16:56:35 +02:00
//this allows to use it in general templates also for complex elements, for which comparison falls back to error
template < int type , typename SORTABLE , typename INDEX , typename PERMINDEX >
int memqsort ( SORTABLE & object , PERMINDEX * perm , INDEX l , INDEX r )
2006-04-01 06:48:01 +02:00
{
INDEX i , j , piv ;
int parity = 0 ;
if ( r < = l ) return parity ; //1 element
2006-04-01 16:56:35 +02:00
if ( LA_sort_traits < SORTABLE , INDEX , type > : : compare ( object , l , r ) ) { parity ^ = 1 ; object . swap ( l , r ) ; if ( perm ) { PERMINDEX tmp = perm [ l ] ; perm [ l ] = perm [ r ] ; perm [ r ] = tmp ; } }
2006-04-01 06:48:01 +02:00
if ( r - l = = 1 ) return parity ; //2 elements and preparation for median
2006-04-01 16:56:35 +02:00
piv = l + ( r - l ) / 2 ; //pivoting by median of 3 - safer
if ( LA_sort_traits < SORTABLE , INDEX , type > : : compare ( object , l , piv ) ) { parity ^ = 1 ; object . swap ( l , piv ) ; if ( perm ) { PERMINDEX tmp = perm [ l ] ; perm [ l ] = perm [ piv ] ; perm [ piv ] = tmp ; } } //and change the pivot element implicitly
if ( LA_sort_traits < SORTABLE , INDEX , type > : : compare ( object , piv , r ) ) { parity ^ = 1 ; object . swap ( r , piv ) ; if ( perm ) { PERMINDEX tmp = perm [ r ] ; perm [ r ] = perm [ piv ] ; perm [ piv ] = tmp ; } } //and change the pivot element implicitly
2006-04-01 06:48:01 +02:00
if ( r - l = = 2 ) return parity ; //in the case of 3 elements we are finished too
//general case , l-th r-th already processed
i = l + 1 ; j = r - 1 ;
do {
//important sharp inequality - stops at sentinel element for efficiency
// this is inefficient if all keys are equal - unnecessary n log n swaps are done, but we assume that it is atypical input
2006-04-01 14:58:57 +02:00
while ( LA_sort_traits < SORTABLE , INDEX , type > : : compare ( object , piv , i + + ) ) ;
2006-04-01 06:48:01 +02:00
i - - ;
2006-04-01 14:58:57 +02:00
while ( LA_sort_traits < SORTABLE , INDEX , type > : : compare ( object , j - - , piv ) ) ;
2006-04-01 06:48:01 +02:00
j + + ;
if ( i < j )
{
// swap and keep track of position of pivoting element
2006-04-01 16:56:35 +02:00
parity ^ = 1 ; object . swap ( i , j ) ; if ( perm ) { PERMINDEX tmp = perm [ i ] ; perm [ i ] = perm [ j ] ; perm [ j ] = tmp ; }
if ( i = = piv ) piv = j ; else if ( j = = piv ) piv = i ;
}
if ( i < = j ) { i + + ; j - - ; }
} while ( i < = j ) ;
if ( j - l < r - i ) //because of the stack in bad case process first the shorter subarray
{ if ( l < j ) parity ^ = memqsort < type , SORTABLE , INDEX , PERMINDEX > ( object , perm , l , j ) ; if ( i < r ) parity ^ = memqsort < type , SORTABLE , INDEX , PERMINDEX > ( object , perm , i , r ) ; }
else
{ if ( i < r ) parity ^ = memqsort < type , SORTABLE , INDEX , PERMINDEX > ( object , perm , i , r ) ; if ( l < j ) parity ^ = memqsort < type , SORTABLE , INDEX , PERMINDEX > ( object , perm , l , j ) ; }
return parity ;
}
template < typename S , typename PERMINDEX >
int ptrqsortup ( S * l , S * r , PERMINDEX * perm = NULL )
{
S * i , * j , * piv ;
int parity = 0 ;
if ( r - l < = 0 ) return parity ; //1 element
if ( * l > * r ) { parity ^ = 1 ; { S tmp ; tmp = * l ; * l = * r ; * r = tmp ; } if ( perm ) { PERMINDEX tmp = * perm ; * perm = perm [ r - l ] ; perm [ r - l ] = tmp ; } }
if ( r - l = = 1 ) return parity ; //2 elements and preparation for median
piv = l + ( r - l ) / 2 ; //pivoting by median of 3 - safer
if ( * l > * piv ) { parity ^ = 1 ; { S tmp ; tmp = * l ; * l = * piv ; * piv = tmp ; } if ( perm ) { PERMINDEX tmp = * perm ; * perm = perm [ piv - l ] ; perm [ piv - l ] = tmp ; } } //and change the pivot element implicitly
if ( * piv > * r ) { parity ^ = 1 ; { S tmp ; tmp = * r ; * r = * piv ; * piv = tmp ; } if ( perm ) { PERMINDEX tmp = perm [ r - l ] ; perm [ r - l ] = perm [ piv - l ] ; perm [ piv - l ] = tmp ; } } //and change the pivot element implicitly
if ( r - l = = 2 ) return parity ; //in the case of 3 elements we are finished too
//general case , l-th r-th already processed
i = l + 1 ; j = r - 1 ;
do {
//important sharp inequality - stops at sentinel element for efficiency
// this is inefficient if all keys are equal - unnecessary n log n swaps are done, but we assume that it is atypical input
while ( * piv > * i + + ) ;
i - - ;
while ( * j - - > * piv ) ;
j + + ;
if ( i < j )
{
// swap and keep track of position of pivoting element
parity ^ = 1 ; { S tmp ; tmp = * i ; * i = * j ; * j = tmp ; } if ( perm ) { PERMINDEX tmp = perm [ i - l ] ; perm [ i - l ] = perm [ j - l ] ; perm [ j - l ] = tmp ; }
if ( i = = piv ) piv = j ; else if ( j = = piv ) piv = i ;
}
if ( i < = j ) { i + + ; j - - ; }
} while ( i < = j ) ;
if ( j - l < r - i ) //because of the stack in bad case process first the shorter subarray
{ if ( l < j ) parity ^ = ptrqsortup ( l , j , perm ) ; if ( i < r ) parity ^ = ptrqsortup ( i , r , perm + ( i - l ) ) ; }
else
{ if ( i < r ) parity ^ = ptrqsortup ( i , r , perm + ( i - l ) ) ; if ( l < j ) parity ^ = ptrqsortup ( l , j , perm ) ; }
return parity ;
}
template < typename S , typename PERMINDEX >
int ptrqsortdown ( S * l , S * r , PERMINDEX * perm = NULL )
{
S * i , * j , * piv ;
int parity = 0 ;
if ( r - l < = 0 ) return parity ; //1 element
if ( * l < * r ) { parity ^ = 1 ; { S tmp ; tmp = * l ; * l = * r ; * r = tmp ; } if ( perm ) { PERMINDEX tmp = * perm ; * perm = perm [ r - l ] ; perm [ r - l ] = tmp ; } }
if ( r - l = = 1 ) return parity ; //2 elements and preparation for median
piv = l + ( r - l ) / 2 ; //pivoting by median of 3 - safer
if ( * l < * piv ) { parity ^ = 1 ; { S tmp ; tmp = * l ; * l = * piv ; * piv = tmp ; } if ( perm ) { PERMINDEX tmp = * perm ; * perm = perm [ piv - l ] ; perm [ piv - l ] = tmp ; } } //and change the pivot element implicitly
if ( * piv < * r ) { parity ^ = 1 ; { S tmp ; tmp = * r ; * r = * piv ; * piv = tmp ; } if ( perm ) { PERMINDEX tmp = perm [ r - l ] ; perm [ r - l ] = perm [ piv - l ] ; perm [ piv - l ] = tmp ; } } //and change the pivot element implicitly
if ( r - l = = 2 ) return parity ; //in the case of 3 elements we are finished too
//general case , l-th r-th already processed
i = l + 1 ; j = r - 1 ;
do {
//important sharp inequality - stops at sentinel element for efficiency
// this is inefficient if all keys are equal - unnecessary n log n swaps are done, but we assume that it is atypical input
while ( * piv < * i + + ) ;
i - - ;
while ( * j - - < * piv ) ;
j + + ;
if ( i < j )
{
// swap and keep track of position of pivoting element
parity ^ = 1 ; { S tmp ; tmp = * i ; * i = * j ; * j = tmp ; } if ( perm ) { PERMINDEX tmp = perm [ i - l ] ; perm [ i - l ] = perm [ j - l ] ; perm [ j - l ] = tmp ; }
2006-04-01 06:48:01 +02:00
if ( i = = piv ) piv = j ; else if ( j = = piv ) piv = i ;
}
if ( i < = j ) { i + + ; j - - ; }
} while ( i < = j ) ;
if ( j - l < r - i ) //because of the stack in bad case process first the shorter subarray
2006-04-01 16:56:35 +02:00
{ if ( l < j ) parity ^ = ptrqsortdown ( l , j , perm ) ; if ( i < r ) parity ^ = ptrqsortdown ( i , r , perm + ( i - l ) ) ; }
2006-04-01 06:48:01 +02:00
else
2006-04-01 16:56:35 +02:00
{ if ( i < r ) parity ^ = ptrqsortdown ( i , r , perm + ( i - l ) ) ; if ( l < j ) parity ^ = ptrqsortdown ( l , j , perm ) ; }
2006-04-01 06:48:01 +02:00
return parity ;
}
2009-11-12 22:01:19 +01:00
} //namespace
2005-09-11 22:04:24 +02:00
# endif