1. 程式人生 > >C語言實現各種排序(1)

C語言實現各種排序(1)

#include<stdio.h>
//排序分為插入排序,希爾排序,氣泡排序,快速排序,選擇排序,堆排序,歸併排序,基數排序(桶排序)

//1.1
//直接插入排序,較為簡單,思路為從第二個數開始逐個將其插入前面有序的序列中
//平均時間複雜度為O(N2),最快時間複雜度為O(N),最壞時間複雜度為O(N2),空間複雜度為O(1)
void InsertSort(int *a,int n) {
	int i;
	for (i = 2; i <= n; i++)
	{
		if (a[i-1] > a[i]) {
			int j = i - 1;
			a[0] = a[i];
			for (; j > 0 && a[j] > a[0]; j--) a[j + 1] = a[j];
			a[j + 1] = a[0];
		}
	}
}

//1.2
//折半插入排序
//思路相同,查詢方法改為折半查詢插入位置
void BInsertSort(int *a, int n)
{
	int i;
	for (i = 2; i <= n; i++)
	{
		if (a[i - 1] > a[i])
		{
			a[0] = a[i];
			int low = 1, high = i - 1;
			while (low <= high)
			{
				int mid = (low + high)/2;
				if (a[mid] > a[0]) high = mid - 1;
				else low = mid + 1;
			}
			int j;
			for (j = i - 1; j > high; j--) {
				a[j + 1] = a[j];
			}
			a[j + 1] = a[0];
		}
	}
}

//1.3
//二路插入排序
//具體實現不再寫,思路為設定一個頭指標為較小的數,設定一個尾指標為較大的數,開始迴圈查詢,若數比頭指標小則插入頭指標前,若比尾指標大
//則插入尾指標後,若在二者之間則利用二分查詢找到合適的插入位置進行位置變換。

//1.4
//希爾排序思路與直接插入排序相似,加入步長概念,原理為排較為有序的序列時時間較短
//平均時間複雜度O(N1.3),空間複雜度為O(1)
void ShellInsert(int *a, int n, int dk)//一趟希爾插入排序,dk為步長
{
	int i;
	for (i = dk + 1; i <= n; i++)
	{
		if (a[i - dk] > a[i])
		{
			a[0] = a[i];
			int j;
			for (j = i - dk; j > 0 && a[j] > a[0]; j -= dk) a[j + dk] = a[j];
			a[j + dk] = a[0];
		}
	}
}

void ShellSort(int *a, int n, int *dlt,int k)//按照增量為dlt[0...k-1]做一次希爾排序
{
	int i = 0;
	for (i = 0; i < k; i++)
	{
		ShellInsert(a, n, dlt[i]);
	}
}

//2.1
//基於交換的排序,氣泡排序法
//平均時間複雜度為O(N2),最壞時間複雜度為O(N2),最好時間複雜度為O(N)
void BubbleSort(int *a, int length)//相當於每次將最大或最小的排到最後一個
{
	for (int i = 0; i < length - 1; i++)
	{
		for (int j = 0; j < length - i - 1; j++)
		{
			if (a[j] > a[j + 1])
			{
				int temp;
				temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}
		}
	}
}

//2.2
//快速排序,設定low和high兩個指標,每次排完後找到一個樞軸,使其左邊為比它小的元素,右邊為比它大的元素;
//再繼續對其左邊和右邊執行這個過程
//平均時間複雜度和最好時間複雜度都為O(N*logN),最壞時間複雜度為O(N2)
int Partition(int *a, int left,int right)
{
	int low = left, high = right;
	int base=a[low];
	while (low < high) {
		while (low<high&&a[high]>=base) high--;
		if (low < high) a[low] = a[high];  
		while (low < high&&a[low] <= base) low++;
		if (low < high) a[high] = a[low];
	}
	a[low] = base;
	return low;
}
void QSort(int *a, int left, int right) {
	if (left < right) {
		int pivotloc = Partition(a, left, right);
		QSort(a, left, pivotloc - 1);
		QSort(a, pivotloc + 1, right);
	}
}

//3.1
//基於選擇的排序
//選擇排序,思路為每次迴圈找到最小的並將其放在陣列頭處
//平均複雜度O(N2),最壞情況O(N2),最好情況O(N)
void SelectSort(int *a, int n)
{
	int i, j;
	int min, temp;
	for (i = 0; i < n-1; i++)
	{
		min = i;
		for (j = i; j < n; j++)
		{
			if (a[j] < a[min]) min = j;
		}
		temp = a[min];
		a[min] = a[i];
		a[i] = temp;
	}
}

//3.2
//堆排序 思路:建立堆,初始化堆,每次輸出堆頂後將最後一個節點與堆頂互換,重新調整堆
//該排序為從小到大排序
//平均最壞最好時間複雜度都為O(N*logN)
typedef struct Heap {
	int length;
	int *elem;
}Heap;

void HeapAdjust(Heap H,int s,int m)//調整使其成為一個大頂堆
{
	int largest;
	int temp;
	int lc = 2 * s;
	int rc = lc + 1;
	if (H.elem[lc] > H.elem[s] && lc <= m) largest = lc;
	else largest = s;
	if (H.elem[rc] > H.elem[largest] && rc <= m) largest = rc;
	if (largest != s)
	{
		temp = H.elem[largest];
		H.elem[largest] = H.elem[s];
		H.elem[s] = temp;
		HeapAdjust(H, largest, m);
	}
}

void HeapSort(Heap H)
{
	int i, temp;
	for (i = H.length / 2; i > 0; i--)
	{
		HeapAdjust(H, i, H.length);
	}//初始化堆
	for (i = H.length; i > 1; i--)
	{
		temp = H.elem[1];
		H.elem[1] = H.elem[i];
		H.elem[i] = temp;
		HeapAdjust(H, 1, i-1);
	}//將堆頂和最後一個互換位置,然後對前i-1個元素重新調整
}

//4.1
//歸併排序,平均最好最壞時間複雜度都為O(N*logN)
//思路對每一部分進行排序,使用的思想是歸併思想,利用分治的策略解決問題
//重複比較加填入的方法



int main()
{
	int a[11] = { 0,3,1,3,2,4,5,6,1,7,13 };
	/*InsertSort(a, 10);*/				//插入排序測試
	/*BInsertSort(a, 10);*/				//二分插入排序測試
	/*int dlt[4] = { 4,3,2,1 };			//希爾排序測試
	ShellSort(a, 10, dlt, 4);*/			
	/*BubbleSort(a + 1, 10);*/			//氣泡排序測試
	/*QSort(a, 1, 10);*/				//快排測試
	/*SelectSort(a+1, 10);*/			//選擇排序測試
	/*Heap H;							//堆排序測試
	H.elem = a;
	H.length = 10;
	HeapSort(H);*/
	for (int i = 1; i < 11; i++)
		printf("%d  ", a[i]);


}