363 lines
12 KiB
C++
363 lines
12 KiB
C++
Sort.h - A collection of sorting and selection routines
|
|
|
|
#ifndef SORT_H_
|
|
#define SORT_H_
|
|
|
|
#define merge Merge
|
|
#define swap Swap
|
|
/**
|
|
* Several sorting routines.
|
|
* Arrays are rearranged with smallest item first.
|
|
*/
|
|
|
|
#include "vector.h"
|
|
|
|
/**
|
|
* Simple insertion sort.
|
|
*/
|
|
template <class Comparable>
|
|
void insertionSort( vector<Comparable> & a )
|
|
{
|
|
/* 1*/ for( int p = 1; p < a.size( ); p++ )
|
|
{
|
|
/* 2*/ Comparable tmp = a[ p ];
|
|
|
|
int j;
|
|
/* 3*/ for( j = p; j > 0 && tmp < a[ j - 1 ]; j-- )
|
|
/* 4*/ a[ j ] = a[ j - 1 ];
|
|
/* 5*/ a[ j ] = tmp;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shellsort, using Shell's (poor) increments.
|
|
*/
|
|
template <class Comparable>
|
|
void shellsort( vector<Comparable> & a )
|
|
{
|
|
for( int gap = a.size( ) / 2; gap > 0; gap /= 2 )
|
|
for( int i = gap; i < a.size( ); i++ )
|
|
{
|
|
Comparable tmp = a[ i ];
|
|
int j = i;
|
|
|
|
for( ; j >= gap && tmp < a[ j - gap ]; j -= gap )
|
|
a[ j ] = a[ j - gap ];
|
|
a[ j ] = tmp;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Standard heapsort.
|
|
*/
|
|
template <class Comparable>
|
|
void heapsort( vector<Comparable> & a )
|
|
{
|
|
/* 1*/ for( int i = a.size( ) / 2; i >= 0; i-- ) /* buildHeap */
|
|
/* 2*/ percDown( a, i, a.size( ) );
|
|
/* 3*/ for( int j = a.size( ) - 1; j > 0; j-- )
|
|
{
|
|
/* 4*/ swap( a[ 0 ], a[ j ] ); /* deleteMax */
|
|
/* 5*/ percDown( a, 0, j );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal method for heapsort.
|
|
* i is the index of an item in the heap.
|
|
* Returns the index of the left child.
|
|
*/
|
|
inline int leftChild( int i )
|
|
{
|
|
return 2 * i + 1;
|
|
}
|
|
|
|
/**
|
|
* Internal method for heapsort that is used in
|
|
* deleteMax and buildHeap.
|
|
* i is the position from which to percolate down.
|
|
* n is the logical size of the binary heap.
|
|
*/
|
|
template <class Comparable>
|
|
void percDown( vector<Comparable> & a, int i, int n )
|
|
{
|
|
int child;
|
|
Comparable tmp;
|
|
|
|
/* 1*/ for( tmp = a[ i ]; leftChild( i ) < n; i = child )
|
|
{
|
|
/* 2*/ child = leftChild( i );
|
|
/* 3*/ if( child != n - 1 && a[ child ] < a[ child + 1 ] )
|
|
/* 4*/ child++;
|
|
/* 5*/ if( tmp < a[ child ] )
|
|
/* 6*/ a[ i ] = a[ child ];
|
|
else
|
|
/* 7*/ break;
|
|
}
|
|
/* 8*/ a[ i ] = tmp;
|
|
}
|
|
|
|
/**
|
|
* Mergesort algorithm (driver).
|
|
*/
|
|
template <class Comparable>
|
|
void mergeSort( vector<Comparable> & a )
|
|
{
|
|
vector<Comparable> tmpArray( a.size( ) );
|
|
|
|
mergeSort( a, tmpArray, 0, a.size( ) - 1 );
|
|
}
|
|
|
|
/**
|
|
* Internal method that makes recursive calls.
|
|
* a is an array of Comparable items.
|
|
* tmpArray is an array to place the merged result.
|
|
* left is the left-most index of the subarray.
|
|
* right is the right-most index of the subarray.
|
|
*/
|
|
template <class Comparable>
|
|
void mergeSort( vector<Comparable> & a,
|
|
vector<Comparable> & tmpArray, int left, int right )
|
|
{
|
|
if( left < right )
|
|
{
|
|
int center = ( left + right ) / 2;
|
|
mergeSort( a, tmpArray, left, center );
|
|
mergeSort( a, tmpArray, center + 1, right );
|
|
merge( a, tmpArray, left, center + 1, right );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal method that merges two sorted halves of a subarray.
|
|
* a is an array of Comparable items.
|
|
* tmpArray is an array to place the merged result.
|
|
* leftPos is the left-most index of the subarray.
|
|
* rightPos is the index of the start of the second half.
|
|
* rightEnd is the right-most index of the subarray.
|
|
*/
|
|
template <class Comparable>
|
|
void merge( vector<Comparable> & a, vector<Comparable> & tmpArray,
|
|
int leftPos, int rightPos, int rightEnd )
|
|
{
|
|
int leftEnd = rightPos - 1;
|
|
int tmpPos = leftPos;
|
|
int numElements = rightEnd - leftPos + 1;
|
|
|
|
// Main loop
|
|
while( leftPos <= leftEnd && rightPos <= rightEnd )
|
|
if( a[ leftPos ] <= a[ rightPos ] )
|
|
tmpArray[ tmpPos++ ] = a[ leftPos++ ];
|
|
else
|
|
tmpArray[ tmpPos++ ] = a[ rightPos++ ];
|
|
|
|
while( leftPos <= leftEnd ) // Copy rest of first half
|
|
tmpArray[ tmpPos++ ] = a[ leftPos++ ];
|
|
|
|
while( rightPos <= rightEnd ) // Copy rest of right half
|
|
tmpArray[ tmpPos++ ] = a[ rightPos++ ];
|
|
|
|
// Copy tmpArray back
|
|
for( int i = 0; i < numElements; i++, rightEnd-- )
|
|
a[ rightEnd ] = tmpArray[ rightEnd ];
|
|
}
|
|
|
|
/**
|
|
* Quicksort algorithm (driver).
|
|
*/
|
|
template <class Comparable>
|
|
void quicksort( vector<Comparable> & a )
|
|
{
|
|
quicksort( a, 0, a.size( ) - 1 );
|
|
}
|
|
|
|
/**
|
|
* Standard swap
|
|
*/
|
|
template <class Comparable>
|
|
inline void swap( Comparable & obj1, Comparable & obj2 )
|
|
{
|
|
Comparable tmp = obj1;
|
|
obj1 = obj2;
|
|
obj2 = tmp;
|
|
}
|
|
|
|
/**
|
|
* Return median of left, center, and right.
|
|
* Order these and hide the pivot.
|
|
*/
|
|
template <class Comparable>
|
|
const Comparable & median3( vector<Comparable> & a, int left, int right )
|
|
{
|
|
int center = ( left + right ) / 2;
|
|
if( a[ center ] < a[ left ] )
|
|
swap( a[ left ], a[ center ] );
|
|
if( a[ right ] < a[ left ] )
|
|
swap( a[ left ], a[ right ] );
|
|
if( a[ right ] < a[ center ] )
|
|
swap( a[ center ], a[ right ] );
|
|
|
|
// Place pivot at position right - 1
|
|
swap( a[ center ], a[ right - 1 ] );
|
|
return a[ right - 1 ];
|
|
}
|
|
|
|
/**
|
|
* Internal quicksort method that makes recursive calls.
|
|
* Uses median-of-three partitioning and a cutoff of 10.
|
|
* a is an array of Comparable items.
|
|
* left is the left-most index of the subarray.
|
|
* right is the right-most index of the subarray.
|
|
*/
|
|
template <class Comparable>
|
|
void quicksort( vector<Comparable> & a, int left, int right )
|
|
{
|
|
/* 1*/ if( left + 10 <= right )
|
|
{
|
|
/* 2*/ Comparable pivot = median3( a, left, right );
|
|
|
|
// Begin partitioning
|
|
/* 3*/ int i = left, j = right - 1;
|
|
/* 4*/ for( ; ; )
|
|
{
|
|
/* 5*/ while( a[ ++i ] < pivot ) { }
|
|
/* 6*/ while( pivot < a[ --j ] ) { }
|
|
/* 7*/ if( i < j )
|
|
/* 8*/ swap( a[ i ], a[ j ] );
|
|
else
|
|
/* 9*/ break;
|
|
}
|
|
|
|
/*10*/ swap( a[ i ], a[ right - 1 ] ); // Restore pivot
|
|
|
|
/*11*/ quicksort( a, left, i - 1 ); // Sort small elements
|
|
/*12*/ quicksort( a, i + 1, right ); // Sort large elements
|
|
}
|
|
else // Do an insertion sort on the subarray
|
|
/*13*/ insertionSort( a, left, right );
|
|
}
|
|
|
|
/**
|
|
* Internal insertion sort routine for subarrays
|
|
* that is used by quicksort.
|
|
* a is an array of Comparable items.
|
|
* left is the left-most index of the subarray.
|
|
* right is the right-most index of the subarray.
|
|
*/
|
|
template <class Comparable>
|
|
void insertionSort( vector<Comparable> & a, int left, int right )
|
|
{
|
|
for( int p = left + 1; p <= right; p++ )
|
|
{
|
|
Comparable tmp = a[ p ];
|
|
int j;
|
|
|
|
for( j = p; j > left && tmp < a[ j - 1 ]; j-- )
|
|
a[ j ] = a[ j - 1 ];
|
|
a[ j ] = tmp;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Quick selection algorithm.
|
|
* Places the kth smallest item in a[k-1].
|
|
* a is an array of Comparable items.
|
|
* k is the desired rank (1 is minimum) in the entire array.
|
|
*/
|
|
template <class Comparable>
|
|
void quickSelect( vector<Comparable> & a, int k )
|
|
{
|
|
quickSelect( a, 0, a.size( ) - 1, k );
|
|
}
|
|
|
|
|
|
/**
|
|
* Internal selection method that makes recursive calls.
|
|
* Uses median-of-three partitioning and a cutoff of 10.
|
|
* Places the kth smallest item in a[k-1].
|
|
* a is an array of Comparable items.
|
|
* left is the left-most index of the subarray.
|
|
* right is the right-most index of the subarray.
|
|
* k is the desired rank (1 is minimum) in the entire array.
|
|
*/
|
|
template <class Comparable>
|
|
void quickSelect( vector<Comparable> & a, int left, int right, int k )
|
|
{
|
|
/* 1*/ if( left + 10 <= right )
|
|
{
|
|
/* 2*/ Comparable pivot = median3( a, left, right );
|
|
|
|
// Begin partitioning
|
|
/* 3*/ int i = left, j = right - 1;
|
|
/* 4*/ for( ; ; )
|
|
{
|
|
/* 5*/ while( a[ ++i ] < pivot ) { }
|
|
/* 6*/ while( pivot < a[ --j ] ) { }
|
|
/* 7*/ if( i < j )
|
|
/* 8*/ swap( a[ i ], a[ j ] );
|
|
else
|
|
/* 9*/ break;
|
|
}
|
|
|
|
/*10*/ swap( a[ i ], a[ right - 1 ] ); // Restore pivot
|
|
|
|
// Recurse; only this part changes
|
|
/*11*/ if( k <= i )
|
|
/*12*/ quickSelect( a, left, i - 1, k );
|
|
/*13*/ else if( k > i + 1 )
|
|
/*14*/ quickSelect( a, i + 1, right, k );
|
|
}
|
|
else // Do an insertion sort on the subarray
|
|
/*15*/ insertionSort( a, left, right );
|
|
}
|
|
|
|
/**
|
|
* Class that wraps a pointer variable.
|
|
*/
|
|
template <class Comparable>
|
|
class Pointer
|
|
{
|
|
public:
|
|
Pointer( Comparable *rhs = NULL ) : pointee( rhs ) { }
|
|
|
|
bool operator<( const Pointer & rhs ) const
|
|
{ return *pointee < *rhs.pointee; }
|
|
operator Comparable * ( ) const
|
|
{ return pointee; }
|
|
private:
|
|
Comparable *pointee;
|
|
};
|
|
|
|
/**
|
|
* Sort objects -- even large ones --
|
|
* with only N + ln N Comparable moves on average.
|
|
*/
|
|
template <class Comparable>
|
|
void largeObjectSort( vector<Comparable> & a )
|
|
{
|
|
vector<Pointer<Comparable> > p( a.size( ) );
|
|
int i, j, nextj;
|
|
|
|
for( i = 0; i < a.size( ); i++ )
|
|
p[ i ] = &a[ i ];
|
|
|
|
quicksort( p );
|
|
|
|
// Shuffle items in place
|
|
for( i = 0; i < a.size( ); i++ )
|
|
if( p[ i ] != &a[ i ] )
|
|
{
|
|
Comparable tmp = a[ i ];
|
|
for( j = i; p[ j ] != &a[ i ]; j = nextj )
|
|
{
|
|
nextj = p[ j ] - &a[ 0 ];
|
|
a[ j ] = *p[ j ];
|
|
p[ j ] = &a[ j ];
|
|
}
|
|
a[ j ] = tmp;
|
|
p[ j ] = &a[ j ];
|
|
}
|
|
}
|
|
|
|
#endif
|