Chapter 7 Sorting

冒泡排序

#include <stdio.h>

typedef int ElementType;
void BubbleSort(ElementType A[], int N)
{
	int i, j, Tmp;
	for (i = 0; i < N - 1; i++)
	{
		for (j = 0; j < N - 1 - i; j++)
		{
			if (A[j] > A[j + 1])
			{
				Tmp = A[j];
				A[j] = A[j + 1];
				A[j + 1] = Tmp;
			}
		}
	}
}
/*
  最好情況:順序O(N);
  最壞情況:逆序O(N2);
  穩定性:穩定;
*/

選擇排序

#include <stdio.h>

typedef int ElementType;

void Swap(ElementType *a, ElementType *b)
{
	ElementType Tmp;
	Tmp = *a;
	*a = *b;
	*b = Tmp;
}
void CelecteSort(ElementType A[], int N)
{
	int i, j;
	for (i = 0; i < N; i++)
	{
		int Min = i;
		for (j = i + 1; j < N; j++)
		{
			if (A[j] < A[Min])
				Min = j;
		}
		Swap(&A[Min], &A[i]);
	}
}

/*
  時間複雜度:O(N^2);
  穩定性:不穩定
*/

插入排序

#include <stdio.h>

typedef int ElementType;
void InsertionSort(ElementType A[], int N)
{
	int j, P;
	ElementType Tmp;
	for (P = 1; P < N; P++)
	{
		Tmp = A[P];
		for (j = P; j > 0 && A[j - 1] > Tmp; j--)
			A[j] = A[j - 1];
		A[j] = Tmp;
	}
}
/*
  最好情況:O(N)
  最差情況:O(N2)
  穩定性:穩定
*/

堆排序

/*
①將關鍵字構造成樹。
②下濾形成初始堆。
*/
#include <stdio.h>
#include <stdlib.h>
#define LeftChild(i)(2 * (i) + 1)

typedef int ElementType;
void Swap(ElementType *a, ElementType *b)
{
	ElementType Tmp;
	Tmp = *a;
	*a = *b;
	*b = Tmp;
}

void PercDown(ElementType A[], int i, int N)
{
	int Child;
	ElementType Tmp;

	for (Tmp = A[i]; LeftChild(i) < N; i = Child)           //取出根節點存放的值
	{
		Child = LeftChild(i);                           //得到左孩子的值
		if (Child != N - 1 && A[Child + 1] > A[Child])  //取左右孩子中較大的
			Child++; 
		if (Tmp < A[Child])      //下濾
			A[i] = A[Child];
		else                     //找到合適位置            
			break;
	}
	A[i] = Tmp;                      //賦值
}

void HeapSort(ElementType A[], int N)
{
	int i;
	ElementType Tmp;
	for (i = N / 2; i >= 0; i--)     //從最後一個不爲葉子的節點開始下濾
		PercDown(A, i, N);
	for (i = N - 1; i > 0; i--)   
	{
		Swap(&A[0], &A[i]);      //“刪除”最大根
		PercDown(A, 0, i);       //調整大根堆
	}
}

/*
  時間複雜度:O(NlogN)
  穩定性:不穩定
*/

歸併排序

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;

//將有序的A[Lpos]~A[Rpos-1]和A[Rpos]~A[RightEnd]歸併成一個有序序列
void Merge(ElementType A[], ElementType TmpArray[], int Lpos, int Rpos, int RightEnd)
{
	// Lpos = 左邊起始位置, Rpos = 右邊起始位置, RightEnd = 右邊終點位置
	int i, LeftEnd, NumElements, TmpPos;
	LeftEnd = Rpos - 1;                   //左邊終點位置
	TmpPos = Lpos;                        //有序序列的起始位置
	NumElements = RightEnd - Lpos + 1;

	while (Lpos <= LeftEnd && Rpos <= RightEnd)              
	{
		if (A[Lpos] <= A[Rpos])
			TmpArray[TmpPos++] = A[Lpos++];//將左邊元素複製到TmpA
		else
			TmpArray[TmpPos++] = A[Rpos++];//將右邊元素複製到TmpA
	}

	while (Lpos <= LeftEnd)                                  
		TmpArray[TmpPos++] = A[Lpos++];  //直接複製左邊剩下的
	while (Rpos <= RightEnd)                                 
		TmpArray[TmpPos++] = A[Rpos++];  //直接複製右邊剩下的

	for (i = 0; i < NumElements; i++, RightEnd--)            
		A[RightEnd] = TmpArray[RightEnd]; //將有序的TmpA[]複製回A[] 
}

//遞歸實現
void MSort_Recursion(ElementType A[], ElementType TmpArray[], int Left, int Right)
{
	int Center;
	if (Left < Right)
	{
		Center = (Left + Right) / 2;                  
		MSort_Recursion(A, TmpArray, Left, Center);            //遞歸解決左邊
		MSort_Recursion(A, TmpArray, Center + 1, Right);       //遞歸解決右邊
		Merge(A, TmpArray, Left, Center + 1, Right); //合併兩段有序序列
	}
}

void MergeSort_Recursion(ElementType A[], int N)
{
	ElementType  *TmpArray;
	TmpArray = (ElementType*)malloc(sizeof(ElementType) * N);  
	if (TmpArray != NULL)
	{
		MSort_Recursion(A, TmpArray, 0, N - 1);
		free(TmpArray);
	}
	else printf("空間不足");
}

//非遞歸實現
//兩兩歸併相鄰有序子列 
void Merge_NonRecursive(ElementType A[], ElementType TmpArray[], int N, int Length)
{ 
	//length = 當前有序子列的長度
	int i, j;

	for (i = 0; i <= N - 2 * Length; i += 2 * Length) //歸併到倒數第二對子列
		Merge(A, TmpArray, i, i + Length, i + 2 * Length - 1);
	if (i + Length < N)                               //歸併最後2個子列(1對+1個)
		Merge(A, TmpArray, i, i + Length, N - 1);
	else                                              //最後只剩1個子列(0對+1個),直接賦給TmpA[]
		for (j = i; j < N; j++) 
			TmpArray[j] = A[j];
}

void MergeSort_NonRecursive(ElementType A[], int N)
{
	int Length;
	ElementType *TmpArray;

	Length = 1;       //初始化子序列長度
	TmpArray = (ElementType*)malloc(N * sizeof(ElementType));
	if (TmpArray != NULL) {
		while (Length < N) { 
			Merge_NonRecursive(A, TmpArray, N, Length);
			Length *= 2;
			Merge_NonRecursive(TmpArray, A, N, Length);
			Length *= 2;
		}             //兩次歸併,保證出循環時,排序後的結果在A[]中
		free(TmpArray);
	}
	else printf("空間不足");
}

/*
  時間複雜度:O(NlogN)
  穩定性:穩定
*/

希爾排序

#include <stdio.h>
#include <math.h>

typedef int ElementType;

/*
  原始希爾排序
  增量元素不互質,則小增量可能根本不起作用
 */
void ShellSort0(ElementType A[], int N)
{
	int i, j, Increment;
	ElementType Tmp;
	for(Increment = N / 2;Increment > 0;Increment /= 2)
	{
		for (i = Increment; i < N; i++)            //插入排序
		{
			Tmp = A[i];
			for (j = i; j >= Increment; j -= Increment)
				if (Tmp < A[j - Increment])
					A[j] = A[j - Increment];
				else
					
					break;
			A[j] = Tmp;
		}
	}
}

/*Hibbard增量序列  
  Dk = 2^k - 1 —— 相鄰元素互質
  {1,3,7,15,31,...}
*/
double log2(double input)
{
	return log(input) / log(2);
}

void ShellSort1(ElementType A[], int N)
{
	int i, j, k, Round, Increment;
	ElementType Tmp;
	for (Round = (int)log2(N); Round > 0; Round--)
	{
		Increment = (int)pow(2, Round) - 1;                //根據公式,計算Hibbard增量
		for (i = Increment; i < N; i++)                    //插入排序
		{
			Tmp = A[i];
			for (j = i; j >= Increment; j -= Increment)
				if (Tmp < A[j - Increment])
					A[j] = A[j - Increment];
				else

					break;
			A[j] = Tmp;
		}
	}
}

/*Sedgewick增量序列
  9 * 4^i - 9 * 2^i + 1 或 4^i - 3 * 2^i - 1
  {1,5,19,41,109,...}
*/
void ShellSort2(ElementType A[], int N)
{
	int i, j, k, Increment;
	ElementType Tmp;
	int Sedgewick[] = { 929, 505, 209, 109, 41, 19, 5, 1, 0 };  // 這裏只列出一小部分增量

	for (k = 0; Sedgewick[k] >= N; k++)
		;                               // 初始的增量Sedgewick[Si]不能超過待排序列長度 
	for (Increment = Sedgewick[k]; Increment > 0; Increment = Sedgewick[++k])
	{
		for (i = Increment; i < N; i++)                    //插入排序
		{
			Tmp = A[i];
			for (j = i; j >= Increment; j -= Increment)
				if (Tmp < A[j - Increment])
					A[j] = A[j - Increment];
				else

					break;
			A[j] = Tmp;
		}
	}
}


/*
  時間複雜度:O(N^d),視增量的選擇而定
  穩定性:不穩定
*/

快速排序

/*①選擇基準(使A[Left] < R[Center] < A[Right],交換A[Center],A[Right-1]。
  ②令 i 從 0 開始向後,j 從 Right - 1 開始向前。
  ③當 A[i] 大於等於基準時,停下,當 A[j] 小於等於基準時,停下。
  ④當 i,j 都停下時,交換指向的元素。
  ⑤當 i > j,退出循環,將基準與 i 指向的元素交換。*/

#include <stdio.h>
#include <stdlib.h>
#define Cutoff 3

typedef int ElementType;
void Swap(ElementType *a, ElementType *b)
{
	ElementType Tmp;
	Tmp = *a;
	*a = *b;
	*b = Tmp;
}

void InsertionSort(ElementType A[], int N)
{
	int j, P;
	ElementType Tmp;
	for (P = 1; P < N; P++)
	{
		Tmp = A[P];
		for (j = P; j > 0 && A[j - 1] > Tmp; j--)
			A[j] = A[j - 1];
		A[j] = 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[Right]一定大於A[Right-1],接下來只需要考慮A[Left+1] … A[Right-2]
	return A[Right - 1];      //返回基準
}

void QSort(ElementType A[], int Left, int Right)
{
	int i, j;
	ElementType Pivot;

	if (Right - Left >= Cutoff)      //如果序列元素大於閾值,進入快速排序
	{
		Pivot = Median3(A, Left, Right);
		i = Left;
		j = Right - 1;
		for (; ;)               //將序列中比基準小的移到基準左邊,大的移到右邊
		{
			while (A[++i] < Pivot) {}   //大於等於基準時退出循環
			while (A[--j] > Pivot) {}   //小於等於基準時退出循環
			if (i < j)
				Swap(&A[i], &A[j]);
			else
				break;
		}
		Swap(&A[i], &A[Right - 1]);//將基準換到正確的位置

		QSort(A, Left, i - 1);     //遞歸解決左邊
		QSort(A, i + 1, Right);    //遞歸解決右邊
	}
	else
		InsertionSort(A + Left, Right - Left + 1); //元素太少,用簡單排序
}

void QuickSort(ElementType A[], int N)
{
	QSort(A, 0, N - 1);
}

/*
時間複雜度:O(NlogN)
穩定性:不穩定
*/

基數排序

#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
/* 基數排序 - 次位優先 */
 
/* 假設元素最多有MaxDigit個關鍵字,基數全是同樣的Radix */
#define MaxDigit 4
#define Radix 10
 
/* 桶元素結點 */
typedef struct Node *PtrToNode;
struct Node {
    int key;
    PtrToNode next;
};
 
/* 桶頭結點 */
struct HeadNode {
    PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
  
int GetDigit ( int X, int D )
{ /* 默認次位D=1, 主位D<=MaxDigit */
    int d, i;
     
    for (i=1; i<=D; i++) {
        d = X % Radix;
        X /= Radix;
    }
    return d;
}
 
void LSDRadixSort( ElementType A[], int N )
{ /* 基數排序 - 次位優先 */
     int D, Di, i;
     Bucket B;
     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);
     } 
}


/* 基數排序 - 主位優先 */
 
/* 假設元素最多有MaxDigit個關鍵字,基數全是同樣的Radix */
 
#define MaxDigit 4
#define Radix 10
 
/* 桶元素結點 */
typedef struct Node *PtrToNode;
struct Node{
    int key;
    PtrToNode next;
};
 
/* 桶頭結點 */
struct HeadNode {
    PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
  
int GetDigit ( int X, int D )
{ /* 默認次位D=1, 主位D<=MaxDigit */
    int d, i;
     
    for (i=1; i<=D; i++) {
        d = X%Radix;
        X /= Radix;
    }
    return d;
}
 
void MSD( ElementType A[], int L, int R, int D )
{ /* 核心遞歸函數: 對A[L]...A[R]的第D位數進行排序 */
     int Di, i, j;
     Bucket B;
     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]號桶 */
         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); 
}



/*時間複雜度:O(P(N+B))
  穩定性:穩定
*/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章