实现:
1 #ifndef SORT_H 2 #define SORT_H 3 4 /** 5 * Several sorting routines. 6 * Arrays are rearranged with smallest item first. 7 */ 8 9 #include <vector> 10 #include <functional> 11 using namespace std; 12 13 /** 14 * Simple insertion sort. 15 * O(N^2) 16 */ 17 template <typename Comparable> 18 void insertionSort( vector<Comparable> & a ) 19 { 20 for( int p = 1; p < a.size( ); p++ ) 21 { 22 Comparable tmp = a[ p ]; 23 24 int j; 25 for( j = p; j > 0 && tmp < a[ j - 1 ]; j-- ) 26 a[ j ] = a[ j - 1 ]; 27 a[ j ] = tmp; 28 } 29 } 30 31 /** 32 * Shellsort, using Shell's (poor) increments. 33 */ 34 template <typename Comparable> 35 void shellsort( vector<Comparable> & a ) 36 { 37 for( int gap = a.size( ) / 2; gap > 0; gap /= 2 ) 38 for( int i = gap; i < a.size( ); i++ ) 39 { 40 Comparable tmp = a[ i ]; 41 int j = i; 42 43 for( ; j >= gap && tmp < a[ j - gap ]; j -= gap ) 44 a[ j ] = a[ j - gap ]; 45 a[ j ] = tmp; 46 } 47 } 48 49 /** 50 * Standard heapsort. 51 */ 52 template <typename Comparable> 53 void heapsort( vector<Comparable> & a ) 54 { 55 for( int i = a.size( ) / 2; i >= 0; i-- ) /* buildHeap */ 56 percDown( a, i, a.size( ) ); 57 for( int j = a.size( ) - 1; j > 0; j-- ) 58 { 59 swap( a[ 0 ], a[ j ] ); /* deleteMax */ 60 percDown( a, 0, j ); 61 } 62 } 63 64 /** 65 * Internal method for heapsort. 66 * i is the index of an item in the heap. 67 * Returns the index of the left child. 68 */ 69 inline int leftChild( int i ) 70 { 71 return 2 * i + 1; 72 } 73 74 /** 75 * Internal method for heapsort that is used in 76 * deleteMax and buildHeap. 77 * i is the position from which to percolate down. 78 * n is the logical size of the binary heap. 79 */ 80 template <typename Comparable> 81 void percDown( vector<Comparable> & a, int i, int n ) 82 { 83 int child; 84 Comparable tmp; 85 86 for( tmp = a[ i ]; leftChild( i ) < n; i = child ) 87 { 88 child = leftChild( i ); 89 if( child != n - 1 && a[ child ] < a[ child + 1 ] ) 90 child++; 91 if( tmp < a[ child ] ) 92 a[ i ] = a[ child ]; 93 else 94 break; 95 } 96 a[ i ] = tmp; 97 } 98 99 /** 100 * Mergesort algorithm (driver). 101 */ 102 template <typename Comparable> 103 void mergeSort( vector<Comparable> & a ) 104 { 105 vector<Comparable> tmpArray( a.size( ) ); 106 107 mergeSort( a, tmpArray, 0, a.size( ) - 1 ); 108 } 109 110 /** 111 * Internal method that makes recursive calls. 112 * a is an array of Comparable items. 113 * tmpArray is an array to place the merged result. 114 * left is the left-most index of the subarray. 115 * right is the right-most index of the subarray. 116 */ 117 template <typename Comparable> 118 void mergeSort( vector<Comparable> & a, 119 vector<Comparable> & tmpArray, int left, int right ) 120 { 121 if( left < right ) 122 { 123 int center = ( left + right ) / 2; 124 mergeSort( a, tmpArray, left, center ); 125 mergeSort( a, tmpArray, center + 1, right ); 126 merge( a, tmpArray, left, center + 1, right ); 127 } 128 } 129 130 /** 131 * Internal method that merges two sorted halves of a subarray. 132 * a is an array of Comparable items. 133 * tmpArray is an array to place the merged result. 134 * leftPos is the left-most index of the subarray. 135 * rightPos is the index of the start of the second half. 136 * rightEnd is the right-most index of the subarray. 137 */ 138 template <typename Comparable> 139 void merge( vector<Comparable> & a, vector<Comparable> & tmpArray, 140 int leftPos, int rightPos, int rightEnd ) 141 { 142 int leftEnd = rightPos - 1; 143 int tmpPos = leftPos; 144 int numElements = rightEnd - leftPos + 1; 145 146 // Main loop 147 while( leftPos <= leftEnd && rightPos <= rightEnd ) 148 if( a[ leftPos ] <= a[ rightPos ] ) 149 tmpArray[ tmpPos++ ] = a[ leftPos++ ]; 150 else 151 tmpArray[ tmpPos++ ] = a[ rightPos++ ]; 152 153 while( leftPos <= leftEnd ) // Copy rest of first half 154 tmpArray[ tmpPos++ ] = a[ leftPos++ ]; 155 156 while( rightPos <= rightEnd ) // Copy rest of right half 157 tmpArray[ tmpPos++ ] = a[ rightPos++ ]; 158 159 // Copy tmpArray back 160 for( int i = 0; i < numElements; i++, rightEnd-- ) 161 a[ rightEnd ] = tmpArray[ rightEnd ]; 162 } 163 164 /** 165 * Quicksort algorithm (driver). 166 */ 167 template <typename Comparable> 168 void quicksort( vector<Comparable> & a ) 169 { 170 quicksort( a, 0, a.size( ) - 1 ); 171 } 172 173 174 /** 175 * Return median of left, center, and right. 176 * Order these and hide the pivot. 177 */ 178 template <typename Comparable> 179 const Comparable & median3( vector<Comparable> & a, int left, int right ) 180 { 181 int center = ( left + right ) / 2; 182 if( a[ center ] < a[ left ] ) 183 swap( a[ left ], a[ center ] ); 184 if( a[ right ] < a[ left ] ) 185 swap( a[ left ], a[ right ] ); 186 if( a[ right ] < a[ center ] ) 187 swap( a[ center ], a[ right ] ); 188 189 // Place pivot at position right - 1 190 swap( a[ center ], a[ right - 1 ] ); 191 return a[ right - 1 ]; 192 } 193 194 /** 195 * Internal quicksort method that makes recursive calls. 196 * Uses median-of-three partitioning and a cutoff of 10. 197 * a is an array of Comparable items. 198 * left is the left-most index of the subarray. 199 * right is the right-most index of the subarray. 200 */ 201 template <typename Comparable> 202 void quicksort( vector<Comparable> & a, int left, int right ) 203 { 204 if( left + 10 <= right ) 205 { 206 Comparable pivot = median3( a, left, right ); 207 208 // Begin partitioning 209 int i = left, j = right - 1; 210 for( ; ; ) 211 { 212 while( a[ ++i ] < pivot ) { } 213 while( pivot < a[ --j ] ) { } 214 if( i < j ) 215 swap( a[ i ], a[ j ] ); 216 else 217 break; 218 } 219 220 swap( a[ i ], a[ right - 1 ] ); // Restore pivot 221 222 quicksort( a, left, i - 1 ); // Sort small elements 223 quicksort( a, i + 1, right ); // Sort large elements 224 } 225 else // Do an insertion sort on the subarray 226 insertionSort( a, left, right ); 227 } 228 229 /** 230 * Internal insertion sort routine for subarrays 231 * that is used by quicksort. 232 * a is an array of Comparable items. 233 * left is the left-most index of the subarray. 234 * right is the right-most index of the subarray. 235 */ 236 template <typename Comparable> 237 void insertionSort( vector<Comparable> & a, int left, int right ) 238 { 239 for( int p = left + 1; p <= right; p++ ) 240 { 241 Comparable tmp = a[ p ]; 242 int j; 243 244 for( j = p; j > left && tmp < a[ j - 1 ]; j-- ) 245 a[ j ] = a[ j - 1 ]; 246 a[ j ] = tmp; 247 } 248 } 249 250 /** 251 * Quick selection algorithm. 252 * Places the kth smallest item in a[k-1]. 253 * a is an array of Comparable items. 254 * k is the desired rank (1 is minimum) in the entire array. 255 */ 256 template <typename Comparable> 257 void quickSelect( vector<Comparable> & a, int k ) 258 { 259 quickSelect( a, 0, a.size( ) - 1, k ); 260 } 261 262 263 /** 264 * Internal selection method that makes recursive calls. 265 * Uses median-of-three partitioning and a cutoff of 10. 266 * Places the kth smallest item in a[k-1]. 267 * a is an array of Comparable items. 268 * left is the left-most index of the subarray. 269 * right is the right-most index of the subarray. 270 * k is the desired rank (1 is minimum) in the entire array. 271 */ 272 template <typename Comparable> 273 void quickSelect( vector<Comparable> & a, int left, int right, int k ) 274 { 275 if( left + 10 <= right ) 276 { 277 Comparable pivot = median3( a, left, right ); 278 279 // Begin partitioning 280 int i = left, j = right - 1; 281 for( ; ; ) 282 { 283 while( a[ ++i ] < pivot ) { } 284 while( pivot < a[ --j ] ) { } 285 if( i < j ) 286 swap( a[ i ], a[ j ] ); 287 else 288 break; 289 } 290 291 swap( a[ i ], a[ right - 1 ] ); // Restore pivot 292 293 // Recurse; only this part changes 294 if( k <= i ) 295 quickSelect( a, left, i - 1, k ); 296 else if( k > i + 1 ) 297 quickSelect( a, i + 1, right, k ); 298 } 299 else // Do an insertion sort on the subarray 300 insertionSort( a, left, right ); 301 } 302 303 /** 304 * Class that wraps a pointer variable. 305 */ 306 template <typename Comparable> 307 class Pointer 308 { 309 public: 310 Pointer( Comparable *rhs = NULL ) : pointee( rhs ) { } 311 312 bool operator<( const Pointer & rhs ) const 313 { return *pointee < *rhs.pointee; } 314 315 operator Comparable * ( ) const 316 { return pointee; } 317 private: 318 Comparable *pointee; 319 }; 320 321 /** 322 * Sort objects -- even large ones -- 323 * with only N + ln N Comparable moves on average. 324 */ 325 template <typename Comparable> 326 void largeObjectSort( vector<Comparable> & a ) 327 { 328 vector<Pointer<Comparable> > p( a.size( ) ); 329 int i, j, nextj; 330 331 for( i = 0; i < a.size( ); i++ ) 332 p[ i ] = &a[ i ]; 333 334 quicksort( p ); 335 336 // Shuffle items in place 337 for( i = 0; i < a.size( ); i++ ) 338 if( p[ i ] != &a[ i ] ) 339 { 340 Comparable tmp = a[ i ]; 341 for( j = i; p[ j ] != &a[ i ]; j = nextj ) 342 { 343 nextj = p[ j ] - &a[ 0 ]; 344 a[ j ] = *p[ j ]; 345 p[ j ] = &a[ j ]; 346 } 347 a[ j ] = tmp; 348 p[ j ] = &a[ j ]; 349 } 350 } 351 352 /* 353 * This is the guts of the generic insertion sort routine. 354 * It is logically a private routine. 355 * It requires a beginning and ending iterator, 356 * a comparison function object, 357 * and a dummy parameter that is used to establish 358 * the type of objects that are in the container. 359 */ 360 template <typename RandomIterator, typename Comparator, typename Object> 361 void insertionSort( const RandomIterator & begin, 362 const RandomIterator & end, 363 Comparator lessThan, 364 const Object & obj ) 365 { 366 RandomIterator j; 367 368 for( RandomIterator p = begin+1; p != end; ++p ) 369 { 370 Object tmp = *p; 371 for( j = p; j != begin && lessThan( tmp, *( j-1 ) ); --j ) 372 *j = *(j-1); 373 *j = tmp; 374 } 375 } 376 377 /* 378 * This is the more public version of insertion sort. 379 * It requires a pair of iterators and a comparison 380 * function object. It calls the four parameter version 381 * by sending *begin as the additional parameter. 382 * The template expansion will allow the routine 383 * above to then deduce Object, on the basis of *begin. 384 */ 385 template <typename RandomIterator, typename Comparator> 386 void insertionSort( const RandomIterator & begin, 387 const RandomIterator & end, 388 Comparator lessThan ) 389 { 390 if( begin != end ) 391 insertionSort( begin, end, lessThan, *begin ); 392 } 393 394 /* 395 * The two-parameter version logically would call 396 * the three parameter version, and send in a 397 * default function object. The function object 398 * would be less<Object>, but what is Object? 399 * We don't know, so we pass *begin to another 400 * version of insertionSort to deduce it. 401 */ 402 template <typename RandomIterator> 403 void insertionSort( const RandomIterator & begin, 404 const RandomIterator & end ) 405 { 406 if( begin != end ) 407 insertionSortHelp( begin, end, *begin ); 408 } 409 410 /* 411 * The three-parameter helper 412 * uses Object to construct less<Object>, and 413 * calls the three-parameter version of insertionSort. 414 */ 415 template <typename RandomIterator, typename Object> 416 void insertionSortHelp( const RandomIterator & begin, 417 const RandomIterator & end, 418 const Object & obj ) 419 { 420 insertionSort( begin, end, less<Object>( ) ); 421 } 422 423 424 #endif
测试:
1 #include <iostream> 2 #include "Sort.h" 3 #include <vector> 4 #include "Random.h" 5 6 using namespace std; 7 8 void checkSort( const vector<int> & a ) 9 { 10 for( int i = 0; i < a.size( ); i++ ) 11 if( a[ i ] != i ) 12 cout << "Error at " << i << endl; 13 cout << "Finished checksort" << endl; 14 } 15 16 17 void permute( vector<int> & a ) 18 { 19 static Random r; 20 21 for( int j = 1; j < a.size( ); j++ ) 22 swap( a[ j ], a[ r.randomInt( 0, j ) ] ); 23 } 24 25 26 int main( ) 27 { 28 const int NUM_ITEMS = 1000; 29 30 vector<int> a( NUM_ITEMS ); 31 for( int i = 0; i < a.size( ); i++ ) 32 a[ i ] = i; 33 34 for( int theSeed = 0; theSeed < 20; theSeed++ ) 35 { 36 permute( a ); 37 insertionSort( a ); 38 checkSort( a ); 39 40 permute( a ); 41 insertionSort( a.begin( ), a.end( ) ); 42 checkSort( a ); 43 44 permute( a ); 45 heapsort( a ); 46 checkSort( a ); 47 48 permute( a ); 49 shellsort( a ); 50 checkSort( a ); 51 52 permute( a ); 53 mergeSort( a ); 54 checkSort( a ); 55 56 permute( a ); 57 quicksort( a ); 58 checkSort( a ); 59 60 permute( a ); 61 largeObjectSort( a ); 62 checkSort( a ); 63 64 permute( a ); 65 quickSelect( a, NUM_ITEMS / 2 ); 66 cout << a[ NUM_ITEMS / 2 - 1 ] << " " << NUM_ITEMS / 2 << endl; 67 } 68 69 return 0; 70 }