1. 程式人生 > >快速排序演算法(QuickSort)

快速排序演算法(QuickSort)

希爾排序是一個比較重要的排序演算法,需要認真的的學習一下,剛開始學習的時候覺得標膠難理解,但是不要放棄,多理解幾遍就好了。記住你每看一遍都會對該演算法有更近一步的瞭解。

一,演算法介紹

設要排序的陣列是A[0]……A[N-1],首先任意選取一個數據(通常選用陣列的第一個數)作為關鍵資料,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱為一趟快速排序。

一趟快速排序的演算法是: 1)設定兩個變數i、j,排序開始的時候:i=0,j=N-1; 2)以第一個陣列元素作為關鍵資料,賦值給key,即key=A[0]; 3)從j開始向前搜尋,即由後開始向前搜尋(j--),找到第一個小於key
的值A[j],將A[j]和A[i]互換; 4)從i開始向後搜尋,即由前開始向後搜尋(i++),找到第一個大於key的A[i],將A[i]和A[j]互換; 5)重複第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[i]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到為止。找到符合條件的值,進行交換的時候i, j指標位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令迴圈結束)。

二,排序演示

假設使用者輸入瞭如下陣列:


建立變數i=0(指向第一個資料), j=5(指向最後一個數據), k=6(賦值為第一個資料的值)。
我們要把所有比k小的數移動到k的左面,所以我們可以開始尋找比6小的數,從j開始,從右往左找,不斷遞減變數j的值,我們找到第一個下標3的資料比6小,於是把資料3移到下標0的位置,把下標0的資料6移到下標3,完成第一次比較:
i=0 j=3 k=6
接著,開始第二次比較,這次要變成找比k大的了,而且要從前往後找了。遞加變數i,發現下標2的資料是第一個比k大的,於是用下標2的資料7和j指向的下標3的資料的6做交換,資料狀態變成下表:

i=2 j=3 k=6

稱上面兩次比較為一個迴圈。 接著,再遞減變數j,不斷重複進行上面的迴圈比較。 在本例中,我們進行一次迴圈,就發現i和j“碰頭”了:他們都指向了下標2。於是,第一遍比較結束。得到結果如下,凡是k(=6)左邊的數都比它小,凡是k右邊的數都比它大:

如果i和j沒有碰頭的話,就遞加i找大的,還沒有,就再遞減j找小的,如此反覆,不斷迴圈。注意判斷和尋找是同時進行的。 然後,對k兩邊的資料,再分組分別進行上述的過程,直到不能再分組為止。 三,程式原始碼
//快速排序
#include<stdio.h>

//待排序記錄的資料的型別
#define MAX_SIZE 20
struct RedType
{
	int key;
	int others;
};
struct SqList //順序表的型別
{
	RedType r[MAX_SIZE+1];//r[0]閒置或者用作哨兵單元
	int length;
};
//交換順序子表L中子表L.r[low..high]的記錄,<span style="color:#ff0000;">使樞軸記錄到位</span>
//並返回其所在的位置,在他之前的記錄都不大於他,在他之後的記錄都不小於他
int Partition(SqList &L,int low,int high)
{
	RedType t;
	int pivotkey;
	pivotkey=L.r[low].key;//用子表的第一個記錄作為樞軸記錄
	while(low < high)
	{
		//從表的兩端交替的向中間掃描
		while(low<high && L.r[high].key>=pivotkey)
		{
			--high;
		}
		//將比樞軸小的記錄交換到低端
		t=L.r[high];
		L.r[high]=L.r[low];
		L.r[low]=t;
		while(low<high && L.r[low].key<=pivotkey)
		{
			++low;
		}
		//將比樞軸記錄大的記錄交換到高階
		t=L.r[high];
		L.r[high]=L.r[low];
		L.r[low]=t;
	}
	<span style="color:#ff0000;">return low;//返回樞軸記錄所在的位置</span>
}
//對順序表L中的<span style="color:#ff0000;">子序列L</span>.r[low..high]作快速排序
void QSort(SqList &L,int low,int high)
{
	int pivotloc;
	if(low < high)
	{
		pivotloc=Partition(L,low,high);
		QSort(L,low,pivotloc-1);//對低子表遞迴排序
		QSort(L,pivotloc+1,high);//對高子表遞迴排序
	}
}
//對順<span style="color:#ff0000;">序表L</span>作快速排序
void QuickSort(SqList &L)
{
	QSort(L,1,L.length);
}
//列印順序表L
void print(SqList L)
{
	int i;
	for(i=1;i<=L.length;i++)
	{
		printf("(%d,%d) ",L.r[i].key,L.r[i].others);
	}
	printf("\n");
}
#define N 8
void main()
{
	SqList l;
	RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{22,7},{49,8}};
	int i;
	l.length=N;
	for(i=0;i<=l.length;i++)
		l.r[i+1]=d[i];
	printf("排序前:");
	print(l);
	QuickSort(l);
	printf("排序後:");
	print(l);
}

四,為了幫助你更好地理解該演算法,提供瞭如下的一張圖,結合著改圖理解一下函式Partition(SqList &L,int low,int high)
五,執行結果