1. 程式人生 > >常見排序演算法的整理

常見排序演算法的整理

一直以來對排序演算法沒有深刻的理解,只能簡單的程式碼編寫,因此今天抽出一些時間對以前排序的不足加以修改。

這裡我們來探討一下常用的比較排序演算法,下表給出了常見比較排序演算法的效能:

穩定性的判別:如果說排序前兩個相等的數位置是a,b,排序後兩個數仍然是a,b,則說明這個排序是穩定的。通俗來講就是說:排序前後兩個相等的數相對位置不發生改變。

氣泡排序:

1.比較相鄰的元素,如果前者大於後者,則將兩個數進行交換。

2.對每一對相鄰元素都做相同的工作,從第一對到最後一對,這步做完之後,最後一個元素便是最大值。

3.針對所有元素都重複以上步驟,每重複一次,便對相鄰比較次數減一。

4.直到沒有相鄰元素比較即完成了氣泡排序。

程式碼實現:

//氣泡排序
//時間複雜度O(N^2)
//空間複雜度O(1)
//穩定性:穩定
void BubbleSort(int array[], int size)
{
	int i, j;
	for (i = 0; i < size-1; i++)
	{
		for (j = 0; j < size - 1 - i; j++)
		{
			if (array[j] > array[j + 1])
				swap(&array[j], &array[j + 1]);
		}
	}
}

選擇排序:

1.從第一個元素開始,然後與所有元素進行比較。

2.遇到比他小的進行交換,一直比較完所有元素,得到最小的那個元素。

3.除了最小的那個元素,其餘重複以上步驟,直到只剩一個元素為止。

程式碼實現:

//選擇排序
//時間複雜度O(n^2)
//空間複雜度O(1)
//穩定性:不穩定
void SelectSort(int array[], int size)
{
	int i = 0;
	for (; i < size; i++)
	{
		for (int j = i; j < size; j++)
		{
			if (array[i]<array[j])
			{
				swap(&array[i], &array[j]);
			}
		}
	}
}

 

插入排序:

1.首先預設第一個元素已經排好序,然後取出下一個元素。

2.將排好序的元素進行從後往前遍歷,如果說已排序的元素大於新元素,則進行搬運,將該元素移到下一位置。

3.繼續遍歷,直到元素小於新元素時,將新元素插入到元素後面。

4.重複以上步驟。直到所有元素比較完成。

程式碼實現:

//插入排序
//時間複雜度O(N^2)
//空間複雜度O(1)
//穩定性:穩定
void InsertSort(int array[], int size)
{
	if (size <= 1)
		return;
	int bound = 1;//[0,bound)有序空間
	for (; bound < size; bound++)
	{
		int bound_value = array[bound];
		int i = bound;
		for (; i>0; i--)
		{
			if (array[i - 1] < bound_value)
			{
				array[i] = array[i - 1];//進行搬運
			}
			else{
				break;
			}
		}
		array[i] = bound_value;
	}
}

堆排序:

1.用給定的無序陣列建一個大堆。

2.每次將堆頂元素與最後一個數進行交換。

3.將堆的大小減一,進行重新調整,直到只剩一個元素。

程式碼實現:

//堆排序
//時間複雜度O(nlogn)
//空間複雜度O(1)
//穩定性:不穩定
void AdjustDown(int array[], int size, int index)//向下調整,大堆
{
	int parent = index;
	int child = 2 * index + 1;
	while (child < size){
		if (child + 1 < size&&array[child] < array[child + 1])
		{
			child = child + 1;
		}
		if (array[parent]<array[child])
		{
			swap(&array[parent], &array[child]);
		}
		else{
			break;
		}
		parent = child;
		child = 2 * child + 1;
	}
	return;
}
void HeapCreate(int array, int size)
{
	if (size <= 1)
		return;
	int i = (size - 1 - 1) / 2;
	for (; i >= 0; i--)
	{
		AdjustDown(array, size, i);
	}
}
void HeapPop(int array[], int size)
{
	if (size <= 1)
		return;
	swap(&array[0], &array[size - 1]);
	AdjustDown(array, size-1,0);
}
void HeapSort(int array[], int size)
{
	if (size <= 1)
		return;
	HeapCreate(array, size);

	int i = 0;
	for (; i < size; i++)
	{
		HeapPop(array, size - i);
	}
}

 

歸併排序:

1.申請同等大小的空間,將陣列拆分為一小塊連續的空間(其實也就是拆成1)。

2.設定兩個指標,最初為止為兩個已排好序陣列的起始位置。

3.比較兩個指標所指向的內容,將較小的元素放入到新的空間當中,並且指標向後移動。

4.重複3,直到有一指標指向排好序的末尾。

5.將另一陣列剩餘的元素全都放入新陣列當中。

程式碼實現:

//歸併排序
//時間複雜度O(nlogn)
//空間複雜度O(N)
//穩定性:穩定
void MergeArray(int array[], int beg, int mid, int end, int *tmp)
{
	int output = beg;
	int cur1 = beg;
	int cur2 = mid;
	while (cur1 < mid&&cur2 < end)
	{
		if (array[cur1] < array[cur2])
		{
			tmp[output++] = array[cur1++];//將較小值放入新空間
		}
		else{
			tmp[output++] = array[cur2++];
		}
	}
	while (cur1 < mid)
	{
		tmp[output++] = array[cur1++];
	}
	while (cur2 < end)
	{
		tmp[output++] = array[cur2++];
	}
	memcpy(array + beg, tmp + beg, sizeof(int)*(end - beg));//還給原空間
}
void _MergeSort(int array, int beg, int end, int *tmp)
{
	if (end - beg <= 1)
		return;
	int mid = beg + (end - beg) / 2;//分割
	_MergeSort(array, beg, mid, tmp);
	_MergeSort(array, mid, end, tmp);

	MergeArray(array, beg, mid, end, tmp);
}
void MergeSort(int array[], int size)
{
	int *tmp = (int *)malloc(sizeof(int)*size);//建立新空間
	_MergeSort(array, 0, size, tmp);
	free(tmp);
}

 

快速排序:

1.首先選一個元素,作為它的基準值。

2.定義兩個指標,一個指向陣列的起始,一個指向陣列的末尾。

3.起始指標從前向後移動,找到第一個大於基準值的值,末尾指標從後往前走,找到第一個小於它的值。進行交換。

4.當兩個指標交叉時,迴圈結束。交換起始指標指向的值和基準值的值。

5.返回基準值的下標。得到基準值前面的元素都比基準值小,後面的元素都比基準值大。

6.將基準值前面元素和後面元素進行分割槽重複以上步驟。

程式碼實現:

//快速排序
//時間複雜度O(nlogn)
//空間複雜度O(nlogn)
//穩定性:不穩定
int Partion(int array[], int beg, int end)
{
	int left = beg;
	int right = end - 1;
	int tmp = array[end - 1];//基準值
	while (left < right){
		while (left < right&&array[left] <= tmp)//找到第一個大於基準值的數
		{
			++left;
		}
		while (left<right&&array[right]>=tmp)//找到第一個小於基準值的數
		{
			--right;
		}
		if (left < right)
		{
			swap(&array[left], &array[right]);
		}
	}
	swap(&array[left], &array[end-1]);//將得到left左邊都小於array[left],右邊都大於array[left]
	return left;
}
void _QuickSort(int array[], int beg, int end)
{
	if (end - beg <= 1)
		return;
	int mid = Partion(array, beg, end);//分割空間
	_QuickSort(array, beg, mid);
	_QuickSort(array, mid, end);
}
void QuickSort(int array[], int size)
{
	_QuickSort(array, 0, size);
}
int main()
{
	int array[] = { 5, 7, 8, 9, 6, 2, 3, 1 };
	//BubbleSort(array, sizeof(array) / sizeof(array[0]));
	//SelectSort(array, sizeof(array) / sizeof(array[0]));
	//InsertSort(array, sizeof(array) / sizeof(array[0]));
	//HeapSort(array, sizeof(array) / sizeof(array[0]));
	//MergeSort(array, sizeof(array) / sizeof(array[0]));
	QuickSort(array, sizeof(array) / sizeof(array[0]));
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		printf("%d ", array[i]);
	}
	printf("\n");
	system("pause");
	return 0;
}