1. 程式人生 > >快速排序和基數排序

快速排序和基數排序

#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;
}