快速排序和基數排序
阿新 • • 發佈:2019-01-31
#include <stdlib.h> #include <stdio.h> #define MAX 100005 typedef long ElementType; //快速排序-直接呼叫庫函式 //簡單整數排序 int compare ( const void *a, const void *b ) { return ( *(ElementType*)a - *(ElementType*)b ); } //一般情況下,對結構體Node中的某鍵值key排序 //struct Node { // ElementType key1, key2; //} A[MAX]; ////按key1降序排列,若key1相等,則按key2升序排列 //int compare2keys ( const void *a, const void *b ) { // int k; // if( ((const struct Node*)a)->key1 < ((const struct Node*)b)->key1 ) // k = 1; //1說明交換 // else if ( ((const struct Node*)a)->key1 > ((const struct Node*)b)->key1 ) // k = -1; //-1交換 // else { // if ( ((const struct Node*)a)->key2 < ((const struct Node*)b)->key2 ) // k = -1; // else // k = 1; // } // return k; //} //快速排序 void Swap ( ElementType *a, ElementType *b ) { ElementType tmp = *a; *a = *b; *b = tmp; } //元素過少時,使用這個插入排序 void Insertion_Sort( ElementType A[], int N ) { int P, i; ElementType Tmp; for( P = 1; P < N; P++ ) { Tmp = A[P]; //取出未排序序列中的第一個元素 for( i = P; i > 0 && A[i - 1] > Tmp; i-- ) A[i] = A[i - 1]; //依次與已排序序列中的元素比較並右移 A[i] = Tmp; //插入到合適的位置 } } ElementType Median3 ( ElementType A[], int Left, int Right ) { int Center = ( Left + Right ) / 2; if ( A[Left] > A[Center] ) Swap( &A[Left], &A[Center] ); if ( A[Left] > A[Right] ) Swap( &A[Left], &A[Right] ); if ( A[Center] > A[Right] ) Swap( &A[Center], &A[Right] ); //此時 A[Left] <= A[Center] <= A[Right] Swap( &A[Center], &A[Right - 1] ); //將基準Pivot藏到右邊 //只需考慮A[Left + 1] ... A[Right - 2] return A[Right - 1]; } void Qsort ( ElementType A[], int Left, int Right ) { //核心遞迴函式 int Pivot, Cutoff = 100, Low, High; //Cutoff = 0會出錯,如果最後只剩1個元素,做快排會陣列越界 if ( Cutoff <= Right - Left ) { //如果序列元素充分過,進入快排 Pivot = Median3( A, Left, Right ); //選基準 Low = Left; High = Right -1; while (1) { //將序列中比基準小的移到基準左邊,大的移到右邊 while ( A[++Low] < Pivot ) ; while ( A[--High] > Pivot ) ; if ( Low < High ) Swap( &A[Low], &A[High] ); else break; } Swap( &A[Low], &A[Right - 1] ); //將基準換到正確的位置 Qsort( A, Left, Low - 1 ); //遞迴解決左邊 Qsort( A, Low + 1, Right ); //遞迴解決右邊 } else Insertion_Sort( A + Left, Right - Left + 1 ); //元素太少,用簡單排序 } void Quick_Sort ( ElementType A[], int N ) { //統一介面 Qsort( A, 0, N - 1 ); } //基數排序-次位優先-只能排自然數(有負數需分類討論) //假設元素最多有MaxDigit個關鍵字,基數全是同樣的Radix #define MaxDigit 10 #define Radix 10 //桶元素結點 typedef struct Node *PtrToNode; struct Node { int key; PtrToNode next; }; //桶頭結點 struct HeadNode { PtrToNode head, tail; }; typedef struct HeadNode Bucket; int GetDigit ( int X, int D ) { int d, i; for ( i = 1; i <= D; i++ ) { d = X % Radix; X /= Radix; } return d; } void LSDdixSort ( ElementType A[], int N ) { //基數排序-次位優先 int D, Di, i; Bucket B[Radix]; PtrToNode tmp, p, List = NULL; for ( i = 0; i < Radix; i++ ) //初始化每個桶為空連結串列 B[i].head = B[i].tail = NULL; for ( i = 0; i < N; i++ ) { //將原始序列逆序存入初始連結串列List tmp = (PtrToNode)malloc(sizeof(struct Node)); tmp->key = A[i]; tmp->next = List; List = tmp; } //下面開始排序 for ( D = 1; D <= MaxDigit; D++ ) { //對資料的每一位迴圈處理 //下面是分配過程 p = List; while (p) { Di = GetDigit(p->key, D); //獲得當前元素的當前位數字 //從List中摘除 tmp = p; p = p->next; //插入B[Di]號桶尾 tmp->next = NULL; if ( B[Di].head == NULL ) B[Di].head = B[Di].tail = tmp; else { B[Di].tail->next = tmp; B[Di].tail = tmp; } } //下面是收集過程 List = NULL; for ( Di = Radix - 1; Di >= 0; Di-- ) //將每個桶的元素順序收集入List if ( B[Di].head ) { //如果桶不為空 //整桶插入List表頭 B[Di].tail->next = List; List = B[Di].head; B[Di].head = B[Di].tail = NULL; //清空桶 } } //將List倒入A[]並釋放空間 for ( i = 0; i < N; i++ ) { tmp = List; List = List->next; A[i] = tmp->key; free(tmp); } } //基數排序-主位優先 void MSD ( ElementType A[], int L, int R, int D ) { //核心遞迴函式:對A[L]...A[R]的第D位數進行排序 int Di, i ,j; Bucket B[Radix]; PtrToNode tmp, p, List = NULL; if ( D == 0 ) return ; //遞迴終止條件 for ( i = 0; i < Radix; i++ ) //初始化每個桶為空連結串列 B[i].head = B[i].tail = NULL; for ( i = L; i <= R; i++ ) { //將原始序列逆序存入初始連結串列List(不同) tmp = (PtrToNode)malloc(sizeof(struct Node)); tmp->key = A[i]; tmp->next = List; List = tmp; } //下面是分配過程 p = List; while (p) { Di = GetDigit(p->key, D); //獲得當前元素的當前位數字 //從List中摘除 tmp = p; p = p->next; //插入B[Di]號桶(與LSD不同) if ( B[Di].head == NULL ) B[Di].tail = tmp; tmp->next = B[Di].head; B[Di].head = tmp; } //下面是收集過程(不同) i = j = L; //i, j記錄當前要處理的A[]的左右端下標 for ( Di = 0; Di < Radix; Di++ ) { if ( B[Di].head ) {//將非空的桶整桶倒入A[],遞迴排序 p = B[Di].head; while (p) { tmp = p; p = p->next; A[j++] = tmp->key; free(tmp); } //遞迴對該桶資料排序,位數減1 MSD( A, i, j - 1, D - 1 ); i = j; //為下一個桶對應的A[]左端 } } } void MSDRadixSort ( ElementType A[], int N ) { //統一介面 MSD( A, 0, N - 1, MaxDigit ); } //桶排序 #define BucketNumber 100 void Bucket_Sort ( ElementType A[], int N ) { int i; PtrToNode tmp, p, List = NULL; Bucket B[BucketNumber]; for ( i = 0; i < BucketNumber; i++ ) //初始化每個桶為空連結串列 B[i].head = B[i].tail = NULL; for ( i = 0; i < N; i++ ) { //將原始序列逆序存入初始連結串列List tmp = (PtrToNode)malloc(sizeof(struct Node)); tmp->key = A[i]; tmp->next = List; List = tmp; } //分配 p = List; while (p) { //從List中摘除 tmp = p; p = p->next; //插入B[tmp->key]號桶尾 if ( B[tmp->key].head == NULL ) B[tmp->key].tail = tmp; tmp->next = B[tmp->key].head; B[tmp->key].head = tmp; } //收集 List = NULL; for( i = BucketNumber - 1; i >= 0 ; i-- ) //從小到大排序 if ( B[i].head ) { //如果桶不為空 //整桶插入List表頭 B[i].tail->next = List; List = B[i].head; B[i].head = B[i].tail = NULL; //清空桶 } //將List倒入A[]並釋放空間 for ( i = 0; i < N; i++ ) { tmp = List; List = List->next; A[i] = tmp->key; free(tmp); } } int main () { ElementType A[MAX]; int N; scanf("%d", &N); for(int i = 0; i < N; i++) scanf("%ld", &A[i]); //qsort( A, N, sizeof(ElementType), compare ); //Quick_Sort( A, N ); //LSDdixSort( A, N ); //MSDRadixSort( A, N ); Bucket_Sort( A, N ); printf("%d", A[0]); for(int i = 1; i < N; i++) printf(" %d", A[i]); /*int N; scanf("%d", &N); for ( int i = 0; i < N; i++ ) scanf("%ld %ld", &A[i].key1, &A[i].key2); qsort( A, N, sizeof(struct Node), compare2keys ); for ( int i = 0; i < N; i++ ) printf("%ld %ld\n", A[i].key1, A[i].key2);*/ system("pause"); return 0; }