定理: 在最坏情况下,任何比较排序算法都需要做nlgn次比较.
1. 计数排序
基本原理:假设n个输入元素中的每一个都是在0到k区间内的一个整数,其中k为某个整数.当k=O(n)时,排序的运行时间为n.对于每一个输入元素x,确定小于x的元素个数.
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #define SIZE 100 void countingSort( int *A, int *B, int k, int len ); int main( void ) { int A[ SIZE ]; int B[ SIZE ]; int k = 0; int i = 0; memset( B, 0, sizeof( int ) * SIZE ); k = SIZE - 5; srand( ( unsigned int )time( NULL ) ); for ( i = 0; i < SIZE; i++ ){ A[ i ] = rand() % k; } printf("the array is:\n"); for ( i = 0; i < SIZE; i++ ){ printf("%d ", A[ i ] ); if ( 0 == ( i + 1 ) % 10 ){ printf("\n"); } } countingSort( A, B, k, SIZE ); printf("\nafter sort,the array is:\n"); for ( i = 0; i < SIZE; i++ ){ printf("%d ", B[ i ] ); if ( 0 == ( i + 1 ) % 10 ){ printf("\n"); } } printf("\n"); return 0; } void countingSort( int *A, int *B, int k, int len ) { int *C = ( int * )malloc( sizeof( int ) * k ); int i = 0; memset( C, 0, sizeof( int ) * k ); for ( i = 0; i < len; i++ ){ C[ A[ i ] ] += 1; } for ( i = 1; i < k; i++ ){ C[ i ] += C[ i - 1 ]; } for ( i = 0; i < k; i++ ){ C[ i ] -= 1; //下标从0开始,否则B会存在下标越界情况 } for ( i = len - 1; i >= 0; i-- ){ B[ C[ A[ i ] ] ] = A[ i ]; C[ A[ i ] ] -= 1; } free( C ); }
备注:在算法的讨论中,一般下标是从1开始的,而实际的编码却是从0开始,所以要小心下标的越界情况.
2. 基数排序
我们用基数排序对以下英文单词进行排序:COW,DOG,SEA,RUG,ROW,MOB,BOX,TAB,BAR,EAR,TAR,DIG,BIG,TEA,NOW,FOX.
#include <stdio.h> void radixSort( char *A[], int len, int keyLen ); int main( void ) { int i = 0; char *A[] = { "COW", "DOG", "SEA", "RUG", "ROW", "MOB", "BOX", "TAB", "BAR", "EAR", "TAR", "DIG", "BIG", "TEA", "NOW", "FOX" }; int len = sizeof( A ) / sizeof( *A ); int keyLen = 3; //每个单词的长度,这里不考虑长度不同的情况,只是为了更好的说明基数排序 radixSort( A, len, keyLen ); for ( i = 0; i < len; i++ ){ printf("%s ", A[ i ] ); if ( 0 == ( i + 1 ) % 5 ){ printf("\n"); } } printf("\n"); return 0; } void radixSort( char *A[], int len, int keyLen ) { int i = 0; int j = 0; int k = 0; for ( i = keyLen - 1; i >= 0; i-- ){ //插入排序 for ( j = 1; j < len; j++ ){ char keyValue = A[ j ][ i ]; char *key = A[ j ]; k = j - 1; while ( k >= 0 && A[ k ][ i ] > keyValue ){ A[ k + 1 ] = A[ k ]; k -= 1; } A[ k + 1 ] = key; } } }
3. 桶排序
假设有100个数据,放在10个桶中,对每个桶进行排序,然后再合并10个桶.
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #include <limits.h> #define SIZE 100 #define LENBUCKET 10 typedef struct NODE{ int data; struct NODE *link; }Node; void bucketSort( int *A, int len ); void insertNode( Node *node, int value ); int main( void ) { int A[ SIZE ]; int i = 0; srand( ( unsigned int )time( NULL ) ); for ( i = 0; i < SIZE; i++ ){ A[ i ] = rand() % SIZE; } printf("the array is:\n"); for ( i = 0; i < SIZE; i++ ){ printf("%3d ", A[ i ] ); if ( 0 == ( i + 1 ) % 10 ){ printf("\n"); } } bucketSort( A, SIZE ); printf("after sort, the array is:\n"); for ( i = 0; i < SIZE; i++ ){ printf("%3d ", A[ i ] ); if ( 0 == ( i + 1 ) % 10 ){ printf("\n"); } } printf("\n"); return 0; } void bucketSort( int *A, int len ) { Node *B[ LENBUCKET ]; int i = 0; int j = 0; for ( i = 0; i < LENBUCKET; i++ ){ Node *node = ( Node * )malloc( sizeof( Node ) ); node->link = NULL; node->data = INT_MIN; B[ i ] = node; } for ( i = 0; i < len; i++ ){ int index = A[ i ] / ( SIZE / LENBUCKET ); insertNode( B[ index ], A[ i ] ); } for ( i = 0, j = 0; j < LENBUCKET; j++ ){ Node *node = ( Node * )malloc( sizeof( Node ) ); node = B[ j ]->link; while ( NULL != node ){ A[ i++ ] = node->data; node = node->link; } } } void insertNode( Node *node, int value ) { Node *tempNode = ( Node * )malloc( sizeof( Node ) ); tempNode->data = value; tempNode->link = NULL; //为空结点 if ( NULL == node->link ){ node->link = tempNode; } else{ //插入头部 if ( value <= node->link->data ){ tempNode->link = node->link; node->link = tempNode; } else{ Node *prevNode = ( Node * )malloc( sizeof( Node ) ); node = node->link; while ( NULL != node && value > node->data ){ prevNode = node; node = node->link; } tempNode->link = node; prevNode->link = tempNode; } } }
备注:1.一定要模块化,比如插入链表就应该封装成insertNode函数.
2. 对于链表的插入,初始化一个头节点专门用来标识这个链表是良好的设计方法,毕竟C语言只支持传值不支持传址(没有C++中引用).
4. 同时查找最小值和最大值
#include <stdio.h> #include <stdlib.h> #include <time.h> #define SIZE 100 void searchMinMax( int *A, int *minValue, int *maxValue, int len ); int main( void ) { int A[ SIZE ]; int i = 0; int minValue = 0; int maxValue = 0; srand( ( unsigned int )time( NULL ) ); for ( i = 0; i < SIZE; i++ ){ A[ i ] = rand() % SIZE; } searchMinMax( A, &minValue, &maxValue, SIZE ); printf("the array is:\n"); for ( i = 0; i < SIZE; i++ ){ printf("%3d ", A[ i ] ); if ( 0 == ( i + 1 ) % 10 ){ printf("\n"); } } printf("\nthe min value is: %3d\nthe max value is:%3d\n", minValue, maxValue ); return 0; } void searchMinMax( int *A, int *minValue, int *maxValue, int len ) { int i = 0; if ( 0 == len % 2 ){ *minValue = A[ 0 ] < A[ 1 ] ? A[ 0 ] : A[ 1 ]; *maxValue = A[ 0 ] > A[ 1 ] ? A[ 0 ] : A[ 1 ]; } else{ *minValue = *maxValue = A[ 0 ]; } for ( i = 2; i < len; i += 2 ){ if ( A[ i ] < A[ i + 1 ] ){ if ( *minValue > A[ i ] ){ *minValue = A[ i ]; } if ( *maxValue < A[ i + 1 ] ){ *maxValue = A[ i + 1 ]; } } else{ if ( *minValue > A[ i + 1 ] ){ *minValue = A[ i + 1 ]; } if ( *maxValue < A[ i ] ){ *maxValue = A[ i ]; } } } }