1. 程式人生 > >資料結構_快速排序&氣泡排序

資料結構_快速排序&氣泡排序

1.氣泡排序

氣泡排序的思想:重複地走訪要排序的元素列,依次比較兩個相鄰的元素,如果他們的順序(如從小到大、字母從A到Z)錯誤就把他們交換過來。走訪元素要重複地進行,直到沒有相鄰元素需要交換,也就是說該元素已經排序完成。

原理如下:

        1.比較相鄰的元素。如果前者比後者大,就交換他們兩個。

        2.對每一對相鄰元素做同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。

        3.針對所有的元素重複以上的步驟,除了最後一個。

        4.持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。

  值得注意的是,假如給定待排序序列已經有序,如{1,2,4,5,6,7},那麼第一次排序便不會交換相鄰元素。後續比較排序也是。所以,為了減少已經有序的待排序序列的排序時間,我們可以設定一個標誌位flag,初值為1。如果某一次排序過程中有交換元素,便將flag置為0。下一次排序之前又將flag置為1;如果此次排序完成flag仍為1,說明此次排序沒有交換任何元素,那麼證明該序列已經有序,則不需要再繼續進行排序。整個排序過程就完成了。

void BubbleSort(int array[], int size)
{
	for (int i = size - 1; i>0; i--)
	{
		int flag = 1;
		for (int j = 0; j < i; j++)
		{
			if (array[j + 1] < array[j])
			{
				Swap(array + j, array + (j+1));
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}

2.快速排序

快速排序是對氣泡排序的一種改進。其基本思想是通過選擇一個基準值將要排序的資料分成兩個區間,其中一個區間的所有元素都比基準值小,另一個區間的所有元素都比基準值大。然後採用分而治之的方法對這兩部分資料分別進行快速排序,當區間中只剩一個數或者為空時停止此次排序,以此達到整個資料變成有序序列。

快排主要有3種實現方法:hoare法,又稱左右指標法;挖坑法;前後指標法(下面三種方法均以區間右端點所在元素作為基準值)

左右指標法:定義兩個指標,一個從左往右走,尋找比基準值小或等的元素,一個從右往左走,尋找比基準值大或等的元素。當“左指標”停下時,表面此時的元素大於基準值;當“右指標”停下時,表面此時的元素小於基準值。此時交換對應的兩個元素,繼續上述過程。最後當左右指標相等時,交換其中一個元素和基準值,並返回基準值此時的下標。

void Swap(int *a, int *b)
{
	int t = *a;
	*a = *b;
	*b = t;
}

//左右指標法
//以array[right]為基準值
//遍歷區間為[left,right]
int Parition_01(int array[], int left, int right)
{
	int begin = left;
	int end = right;
	while (begin < end)
	{
		while (begin < end && array[begin] <= array[right])
		{
			begin++;
		}
		while (begin < end && array[end] >= array[right])
		{
			end--;
		}
		Swap(array + begin, array + end);
	}
	Swap(array + begin, array + right);
	return begin;
}

挖坑法:先將基準值儲存起來,此時相當於基準值的位置就空出來了。然後定義兩個指標begin和end,其初始值分別為待排序區間的左端點和右端點,begin尋找比基準值大的元素,end尋找比基準值小的元素。當begin找到比基準值大的元素之後,此時將其賦給end所指位置,那麼begin所指位置便又空出來了;當end找到比基準值小的元素之後,此時將其賦給begin所指位置,那麼此時end所指位置又空出來了。重複上述過程,直到begin==end。此時將基準值賦給begin所指位置並返回下標begin。

//挖坑法
int Parition_02(int array[], int left, int right)
{
	int begin = left;
	int end = right;
	int key = array[right];
	while (begin < end)
	{
		while (begin < end && array[begin] <= key)
		{
			begin++;
		}
		array[end] = array[begin];
		while (begin < end && array[end] >= key)
		{
			end--;
		}
		array[begin] = array[end];
	}
	array[begin] = key;
	return begin;
}

前後指標法:定義兩個指標div和cur,初始值均為待排序區間的左端點,其中div所指位置之前表示比基準值小或等的元素,div和cur之間表示比基準值大的元素,cur之後表示待排序部分。在cur遍歷整個待排序區域期間,如果cur所指元素小於div所指元素,則交換,此時div++。最後交換div所指元素和基準值,並返回基準值此時的下標。

void Swap(int *a, int *b)
{
	int t = *a;
	*a = *b;
	*b = t;
}

//前後指標法
int Parition_03(int array[], int left, int right)
{
	int div = left;
	int cur = left;
	for (; cur < right; cur++)
	{
		if (array[cur] <= array[right])
		{
			Swap(array + div, array + cur);
			div++;
		}
	}
	Swap(array + div, array + right);
	return div;
}
void __QuickSort(int array[], int left, int right)
{
	if (left == right)
	{//區間只剩一個數,說明已經有序
		return;
	}
	if (left > right)
	{//區間沒有數了
		return;
	}
	int div = Parition_01(array, left, right);
	__QuickSort(array, left, div - 1);
	__QuickSort(array, div + 1, right);
}

//快排
void QuickSort(int array[], int size)
{
	__QuickSort(array, 0, size - 1);
}