經典排序演算法 創建3個文件:sortArray.h、sortArray.c、sortArrayTest.c。 sortArray.h c include include include "sort.h" // 功能: 列印錯誤信息後就錯誤退出程式. // 參數: expression(錯誤判斷表達式 ...
創建3個文件:sortArray.h、sortArray.c、sortArrayTest.c。
sortArray.h
#ifndef SORT_ARRAY_H_
#define SORT_ARRAY_H_
// 功能: 比較兩個數據.
// 參數: a(數據a), b(數據b).
// 返回: a>b返回正數, a<b返回負數, 否則返回0.
// 註意: 其實返回值可以是任意int類型值, 但是為了統一規範使用所以才強制返回值.
typedef int ( CompareFunc )( const void *a, const void *b );
// 功能: 選擇排序.
// 參數: a(需排序的數組), left(需排序區間的左閉邊界), right(需排序區間的右閉邊界), cmp(自定義比較函數).
// 返回: 無.
// 註意: 當 a 為NULL 或 cmp 為NULL 或 區間範圍表示錯誤 時, 將錯誤退出程式.
extern void selectSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp );
// 功能: 冒泡排序.
// 參數: a(需排序的數組), left(需排序區間的左閉邊界), right(需排序區間的右閉邊界), cmp(自定義比較函數).
// 返回: 無.
// 註意: 當 a 為NULL 或 cmp 為NULL 或 區間範圍表示錯誤 時, 將錯誤退出程式.
extern void bubbleSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp );
// 功能: 插入排序.
// 參數: a(需排序的數組), left(需排序區間的左閉邊界), right(需排序區間的右閉邊界), cmp(自定義比較函數).
// 返回: 無.
// 註意: 當 a 為NULL 或 cmp 為NULL 或 區間範圍表示錯誤 時, 將錯誤退出程式.
extern void insertSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp );
// 功能: 歸併排序.
// 參數: a(需排序的數組), left(需排序區間的左閉邊界), right(需排序區間的右閉邊界), cmp(自定義比較函數).
// 返回: 無.
// 註意: 當 a 為NULL 或 cmp 為NULL 或 區間範圍表示錯誤 時, 將錯誤退出程式.
extern void mergeSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp );
// 功能: 快速排序.
// 參數: a(需排序的數組), left(需排序區間的左閉邊界), right(需排序區間的右閉邊界), cmp(自定義比較函數).
// 返回: 無.
// 註意: 當 a 為NULL 或 cmp 為NULL 或 區間範圍表示錯誤 時, 將錯誤退出程式.
extern void quickSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp );
// 功能: 堆排序.
// 參數: a(需排序的數組), left(需排序區間的左閉邊界), right(需排序區間的右閉邊界), cmp(自定義比較函數).
// 返回: 無.
// 註意: 當 a 為NULL 或 cmp 為NULL 或 區間範圍表示錯誤 時, 將錯誤退出程式.
extern void heapSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp );
// 功能: 計數排序.
// 參數: a(需排序的數組), left(需排序區間的左閉邊界), right(需排序區間的右閉邊界), cmp(自定義比較函數).
// 返回: 無.
// 註意: 當 a 為NULL 或 cmp 為NULL 或 區間範圍表示錯誤 時, 將錯誤退出程式.
extern void countSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp );
// 功能: 基數排序.
// 參數: a(需排序的數組), left(需排序區間的左閉邊界), right(需排序區間的右閉邊界), cmp(自定義比較函數).
// 返回: 無.
// 註意: 當 a 為NULL 或 cmp 為NULL 或 區間範圍表示錯誤 時, 將錯誤退出程式.
extern void radixSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp );
#endif
sortArray.c
#include <stdint.h>
#include <time.h>
#include "sort.h"
// 功能: 列印錯誤信息後就錯誤退出程式.
// 參數: expression(錯誤判斷表達式), message(需列印的錯誤信息).
// 返回: 無.
// 註意: 當expression為真時,才觸發.
#define ERROR_EXIT( expression, message ) \
if( (expression) ) { \
fprintf( stderr, "\nerror location: %s, %s, %u.\n", \
__FILE__, __func__, __LINE__ ); \
fprintf( stderr, "error message: %s.\n", \
!(message) ? __func__ : (message) ); \
exit( EXIT_FAILURE ); \
}
// 功能: 數組的兩個元素進行互換.
// 參數: a(數組首地址), i(數組下標), j(數組下標).
// 返回: 無.
#define SWAP( a, i , j ) \
do { \
int32_t temp = *((a) + (i)); \
*((a) + (i)) = *((a) + (j)); \
*((a) + (j)) = temp; \
} while( 0 )
#define MAX( a, b ) ((a) > (b) ? (a) : (b))
#define MIN( a, b ) ((a) < (b) ? (a) : (b))
selectSortArray
void selectSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t i = 0, m = 0; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); while( left <= right ) { m = left; for( i = left + 1; i <= right; ++i ) { m = cmp( &a[i], &a[m] ) < 0 ? i : m; } if( m != left ) { SWAP( a, left, m ); } ++left; } }
bubbleSortArray
void bubbleSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t i = 0; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); while( left < right ) { for( i = right; i > left; --i ) { if( cmp( &a[i], &a[i - 1] ) < 0 ) { SWAP( a, i, i - 1 ); } } ++left; } }
insertSortArray
void insertSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t i = 0, j = 0; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); for( i = left; i < right; ++i ) { #if 1 for( j = i + 1; j > left && cmp( &a[j], &a[j - 1] ) < 0; --j ) { SWAP( a, j, j - 1 ); } #else for( j = i; j >= left && cmp( &a[j + 1], &a[j] ) < 0; --j ) { SWAP( a, j, j + 1 ); } #endif } }
mergeSortArray
版本一
static void merge( int32_t a[], int32_t left, int32_t middle, int32_t right, CompareFunc *cmp ) { int32_t *tempA = NULL, i = 0, l = left, r = middle + 1; if( left < 0 || left > middle || middle > right ) { return; } tempA = malloc( sizeof(*tempA) * (right - left + 1) ); while( l <= middle && r <= right ) { tempA[i++] = cmp( &a[l], &a[r] ) <= 0 ? a[l++] : a[r++]; } while( l <= middle ) { tempA[i++] = a[l++]; } while( r <= right ) { tempA[i++] = a[r++]; } while( --i >= 0 ) { a[left + i] = tempA[i]; } free( tempA ); } void mergeSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t middle = left + (right - left) / 2; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); if( left >= right ) { return; } mergeSortArray( a, left, middle, cmp ); mergeSortArray( a, middle + 1, right, cmp ); merge( a, left, middle, right, cmp ); }
版本二
static void merge( int32_t a[], int32_t left, int32_t middle, int32_t right, CompareFunc *cmp ) { int32_t *tempA = NULL, i = 0, l = left, r = middle + 1; if( left < 0 || left > middle || middle > right ) { return; } tempA = malloc( sizeof(*tempA) * (right - left + 1) ); while( l <= middle || r <= right ) { if( l <= middle && r <= right ) { tempA[i++] = cmp( &a[l], &a[r] ) <= 0 ? a[l++] : a[r++]; } else if( l <= middle ) { tempA[i++] = a[l++]; } else { tempA[i++] = a[r++]; } } while( --i >= 0 ) { a[left + i] = tempA[i]; } free( tempA ); } void mergeSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t middle = left + (right - left) / 2; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); if( left >= right ) { return; } mergeSortArray( a, left, middle, cmp ); mergeSortArray( a, middle + 1, right, cmp ); merge( a, left, middle, right, cmp ); }
版本三
static void merge( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp, int32_t tempA[] ) { int32_t middle = left + (right - left) / 2; int32_t i = 0, l = left, r = middle + 1; if( left >= right ) { return; } merge( a, left, middle, cmp, tempA ); merge( a, middle + 1, right, cmp, tempA ); while( l <= middle || r <= right ) { if( l <= middle && r <= right ) { tempA[i++] = cmp( &a[l], &a[r] ) <= 0 ? a[l++] : a[r++]; } else if( l <= middle ) { tempA[i++] = a[l++]; } else { tempA[i++] = a[r++]; } } while( --i >= 0 ) { a[left + i] = tempA[i]; } } void mergeSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t *tempA = NULL; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); if( left >= right ) { return; } tempA = malloc( sizeof(*tempA) * (right - left + 1) ); merge( a, left, right, cmp, tempA ); free( tempA ); }
版本四
static void merge( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp, int32_t tempA[] ) { int32_t middle = left + (right - left) / 2; int32_t i = 0, j = 0; if( left >= right ) { return; } merge( a, left, middle, cmp, tempA ); merge( a, middle + 1, right, cmp, tempA ); for( j = 0, i = left; i <= middle; ++i ) { tempA[j++] = a[i]; } // R.Sedgewick的優化方法, 歸併過程中先將後一半逆序再進行歸併. 如: [1,4 | 3,7] 變為 [1,4 | 7,3]. for( i = right; i > middle; --i ) { tempA[j++] = a[i]; } for( i = 0, j = right - left; i <= j; ++left ) { a[left] = cmp( &tempA[i], &tempA[j] ) <= 0 ? tempA[i++] : tempA[j--]; } } void mergeSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t *tempA = NULL; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); if( left >= right ) { return; } tempA = malloc( sizeof(*tempA) * (right - left + 1) ); merge( a, left, right, cmp, tempA ); free( tempA ); }
quickSortArray
版本一
static void partition( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp, int32_t boundary[2] ) { int32_t l = left - 1, c = left, r = right, cmpR = 0; while( c < r ) { cmpR = cmp( &a[c], &a[right] ); if( cmpR < 0 ) { ++l; SWAP( a, l, c ); ++c; } else if( cmpR == 0 ) { ++c; } else { --r; SWAP( a, c, r ); } } SWAP( a, r, right ); boundary[0] = l + 1; boundary[1] = r; } void quickSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t boundary[2] = {-1, -1}, i = 0; srand( time( NULL ) ); ERROR_EXIT( !a || left < 0 || !cmp, NULL ); if( left >= right ) { return; } // left + rand() % (right - left) 取值區間為: [left, right). // left + rand() % (right - left + 1) 取值區間為: [left, right]. i = left + rand() % (right - left); SWAP( a, right, i ); partition( a, left, right, cmp, boundary ); // boundary[0] 表示等於區間的左閉邊界, boundary[1] 表示等於區間的右閉邊界. quickSortArray( a, left, boundary[0] - 1, cmp ); quickSortArray( a, boundary[1] + 1, right, cmp ); }
版本二
void quickSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t i = 0, cmpR = 0, l = left - 1, c = left, r = right; srand( time( NULL ) ); ERROR_EXIT( !a || left < 0 || !cmp, NULL ); if( left >= right ) { return; } // left + rand() % (right - left) 取值區間為: [left, right). // left + rand() % (right - left + 1) 取值區間為: [left, right]. i = left + rand() % (right - left); SWAP( a, right, i ); while( c < r ) { cmpR = cmp( &a[c], &a[right] ); if( cmpR < 0 ) { ++l; SWAP( a, c, l ); ++c; } else if( cmpR == 0 ) { ++c; } else { --r; SWAP( a, c, r ); } } SWAP( a, right, r ); quickSortArray( a, left, l, cmp ); quickSortArray( a, r + 1, right, cmp ); }
heapSortArray
版本一
static void heapinsert( int32_t heap[], int32_t i, CompareFunc *cmp ) { int32_t p = 0; for( p = (i - 1) / 2; cmp( &heap[i], &heap[p] ) > 0; p = (i - 1) / 2 ) { SWAP( heap, p, i ); i = p; } } static void heapify( int32_t heap[], int32_t heapSize, int32_t i, CompareFunc *cmp ) { int32_t l = 0, m = 0; for( l = i * 2 + 1; l < heapSize; l = i * 2 + 1 ) { m = l + 1 < heapSize && cmp( &heap[l + 1], &heap[l] ) > 0 ? l + 1 : l; if( cmp( &heap[i], &heap[m] ) > 0 ) { break; } SWAP( heap, m, i ); i = m; } } void heapSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t i = 0, n = right - left + 1; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); if( left >= right ) { return; } for( i = 0; i < n; ++i ) { heapinsert( &a[left], i, cmp ); } while( --i > 0 ) { SWAP( &a[left], 0, i ); heapify( &a[left], i, 0, cmp ); } }
版本二
void heapSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t i = 0, n = right - left + 1; int32_t p = 0, index = 0, l = 0, m = 0; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); if( left >= right ) { return; } a += left; // 使a指向 a[left] 元素的首地址. for( i = 0; i < n; ++i ) { index = i; p = (index - 1) / 2; for( p = (index - 1) / 2; cmp( &a[index], &a[p] ) > 0; p = (index - 1) / 2 ) { SWAP( a, p, index ); index = p; } } while( --i > 0 ) { SWAP( a, 0, i ); index = 0; for( l = index * 2 + 1; l < i; l = index * 2 + 1 ) { m = l + 1 < i && cmp( &a[l + 1], &a[l] ) > 0 ? l + 1 : l; if( cmp( &a[index], &a[m] ) > 0 ) { break; } SWAP( a, index, m ); index = m; } } }
countSortArray
void countSortArray( int32_t a[], int32_t left, int32_t right, CompareFunc *cmp ) { int32_t *count = NULL, i = 0, j = 0, min = INT32_MAX, max = INT32_MIN; ERROR_EXIT( !a || left < 0 || !cmp, NULL ); for( i = left; i <= right; ++i ) { min = MIN( min, a[i] ); max = MAX( max, a[i] ); } if( min == max ) { return; } count = calloc( sizeof(*count), (max - min + 1) ); for( i = left; i <= right; ++i ) { ++count[a[i] - min]; } if( cmp( &min, &max ) <= 0 ) { for( i = min; i <= max; ++i ) { for( j = count[i - min]; j > 0; --j ) { a[left++] = i; } } } else { for( i = max; i >= min; --i ) { for( j = count[i - min]; j > 0; --j ) { a[left++] = i; } } } free( count ); }
radixSortArray
sortArrayTest.c
實現對數器.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include "sort.h"
#define MAX( a, b ) ((a) > (b) ? (a) : (b))
// 功能: 對數組的某一區間內的元素值進行隨機化.
// 參數: a(數組首地址), left(左閉區間), right(右閉區間), v(最大隨機值).
// 返回: 無.
// 註意: 當v是正數/負數/零時,隨機值的區間分別為[-v, v]/[]/[].
static void randomArray( int32_t a[], int32_t left, int32_t right, int32_t v ) {
v -= v != INT32_MAX ? 0 : 1;
while( left <= right ) {
a[left++] = rand() % (v + 1) - rand() % (v + 1);
}
}
// 功能: 將源數組的某一區間內的元素值拷貝至目的數組中.
// 參數: a(源數組首地址), left(左閉區間), right(右閉區間), b(目的數組首地址).
// 返回: 無.
// 註意: 無.
static void cloneArray( const int32_t a[], int32_t left, int32_t right, int32_t b[] ) {
while( left <= right ) {
b[left] = a[left];
++left;
}
}
// 功能: 將數組的某一區間內的元素值送入到文件流中.
// 參數: a(數組首地址), left(左閉區間), right(右閉區間), fp(文件流指針).
// 返回: 無.
// 註意: 無.
static void printArray( const int32_t a[], int32_t left, int32_t right, FILE *fp ) {
fprintf( fp, "[" );
while( left <= right ) {
fprintf( fp, "%5d%s", a[left], left != right ? ", " : "" );
++left;
}
fprintf( fp, "]\n" );
}
// 功能: 數據比較.
// 參數: a(數據1), b(數據2).
// 返回: a<b返回負數, a>b返回正數, 否則返回0.
// 註意: 無.
static int cmp( const void *a, const void *b ) {
#if 1
return *(int32_t *) a - *(int32_t *) b;
#else
return *(int32_t *) b - *(int32_t *) a;
#endif
}
// 功能: 絕對正確的方法.
// 參數: a(數組首地址), left(左閉區間), right(右閉區間).
// 返回: 無.
// 註意: 使用穩定的庫函數方法 或 非常笨的方法(如暴力迴圈,暴力遞歸搜索).
static void correct( int32_t a[], int32_t left, int32_t right ) {
qsort( &a[left], right - left + 1, sizeof(*a), cmp );
}
// 功能: 待測試的方法.
// 參數: a(數組首地址), left(左閉區間), right(右閉區間).
// 返回: 無.
// 註意: 使用技巧性的高效的正確性未知的方法.
static void test( int32_t a[], int32_t left, int32_t right ) {
selectSortArray( a, left, right, cmp );
//bubbleSortArray( a, left, right, cmp );
//insertSortArray( a, left, right, cmp );
//mergeSortArray( a, left, right, cmp );
//quickSortArray( a, left, right, cmp );
//heapSortArray( a, left, right, cmp );
//countSortArray( a, left, right, cmp );
}
// 功能: 比較兩數組的同區間內的元素是否全部相等.
// 參數: a(數組首地址), b(數組首地址), left(左閉區間), right(右閉區間).
// 返回: 區間內的元素全部相等返回1, 否則返回0.
// 註意: 無.
static int equal( const int32_t a[], const int32_t b[], int32_t left, int32_t right ) {
while( left <= right ) {
if( a[left] != b[left] ) {
return 0;
}
++left;
}
return 1;
}
int main( int argc, char *argv[] ) {
const int32_t times = 7654321; // 測試的總測試.
const int32_t maxSize = 21; // 隨機的最大長度.
int32_t size = 0, left = 0, right = 0;
int32_t *a = NULL, *t = NULL, *c = NULL;
int32_t i = 0;
srand( time( NULL ) );
a = malloc( sizeof(*a) * maxSize );
c = malloc( sizeof(*c) * maxSize );
t = malloc( sizeof(*t) * maxSize );
for( i = 0; i < times; ++i ) {
size = rand() % (maxSize + 1); // 隨機化數組長度.
randomArray( a, 0, size - 1, 321 );
cloneArray( a, 0, size - 1, c );
cloneArray( a, 0, size - 1, t );
left = 0;
right = size - 1;
#if 1 // 隨機化排序區間.
left = rand() % MAX( size, 1 );
do {
right = rand() % MAX( size, 1 );
} while( right < left );
#endif
correct( c, left, right ); // 絕對正確的方法.
test( t, left, right ); // 待測試的方法.
if( !equal( c, t, 0, size - 1 ) ) {
fprintf( stderr, "source :" );
printArray( a, 0, size - 1, stderr );
fprintf( stderr, "correct :" );
printArray( c, 0, size - 1, stderr );
fprintf( stderr, "test :" );
printArray( t, 0, size - 1, stderr );
fprintf( stderr, " 本次測試不通過!\n\a" );
exit( EXIT_FAILURE );
}
}
free( t );
free( c );
free( a );
printf( "總共 %d 次測試且全部通過!\n", times );
return EXIT_SUCCESS;
}
sortArrayTest.sh
# !/bin/bash
for(( i = 1; i <= 21; ++i )) do
printf "%02d" ${i}
echo -n ____________
./sortArrayTest
done