快速排序

1、算法思想

選定一個元素作爲支點(pivot),以支點爲基準將整個序列劃分爲兩個子序列r1 … ri-1和ri+1 … rn,前一個子序列中記錄的值均小於或等於支點,後一個子序列中元素的值均大於或等於支點,這個過程稱作一趟快速排序(如下圖所示)。然後只要分別對這兩部分繼續進行遞歸地排序,就可以使整個序列有序。

一趟快速排序的具體做法:
1)、設置兩個指針low和high,剛開始分別指向序列的第一個、最後一個的元素。初始化支點(pivot)也爲序列的第一個元素。(這是爲了方便編程。這裏有種錯覺:好像pivot只能爲第一個元素。其實是可以取序列中的任意一個元素的,只要將選定的元素和第一個元素交換一下就可以了。)
2)、首先,從high所指定位置起向前搜索找到第一個小於pivot的元素和low所指向的元素(即pivot)互相交換,然後從low所指位置起向後搜索,找到第一個大於pivot的元素和high所指向的元素(即pivot)交換。
3)、重複2)中的兩步,直到low=high

2、基本算法實現

int partition(int data[], int low, int high)  //返回pivot所在的位置
{
	int pivot = data[low];
	while (low < high)
	{
		while (low < high && data[high] >= pivot) high--;
		swap(data[low], data[high]);  //high指向的值比支點值小,換到前面去。和low指向的值交換也就是和pivot交換

		while (low < high && data[low] <= pivot) low++;
		swap(data[low], data[high]);  //low指向的值比支點值大,換到後面去。此時,high指向的值等於pivot
		                               //和high交換也就是和pivot交換
	}
	return low; //此時low == high。可以發現:pivot其實就是不停地在被“丟來丟去”,不是在high處就是在low處。
	             //所以這裏返回high也可以。這也解釋了爲什麼low == high時,算法就停止了,因爲low和high指向的value已經是pivot了。
}

void QSort(int data[], int low, int high)     //完整快速排序
{
	if (low < high)
	{
		int pivotloc = partition(data, low, high);
		QSort(data, low, pivotloc - 1);       //遞歸
		QSort(data, pivotloc + 1, high);      //遞歸
	}
}

int main(int argc, char *argv[])
{
	int data[20] = { 1, 7, 3, 50, 43, 34, 78, 23, 67, 90 };
	QSort(data, 0, 9);  //調用快排
	int i = 0;
	while (i < 10)   //輸出
	{
		cout << data[i] << ' ';
		++i;
	}
	system("pause");
	return 0;
}

3、改進快排算法

上面算法中,每交換一對記錄需要進行3次記錄移動操作(即swap函數)。從代碼和註釋中可以看出,其實pivot一直在被“丟來丟去”,所以沒有必要一直移動pivot,也就是可以將pivot暫存起來,然後將pivot賦值到最終的位置(一共就修改了4行代碼:第5、9、12、14行)。修改版代碼如下:
//微改進快排
int partition(int data[], int low, int high)  //返回pivot所在的位置
{
	int pivot = data[low];
	data[0] = pivot;  //暫存
	while (low < high)
	{
		while (low < high && data[high] >= pivot) high--;
		data[low] = data[high];  //第一次執行時,覆蓋了pivot,因爲pivot已經暫存到data[0]處

		while (low < high && data[low] <= pivot) low++;
		data[high] = data[low];   //由於上一步的執行,data[high]已經複製到了low處
	}
	data[low] = data[0];
	return low;
}

void QSort(int data[], int low, int high)     //完整快速排序
{
	if (low < high)
	{
		int pivotloc = partition(data, low, high);
		QSort(data, low, pivotloc - 1);       //遞歸
		QSort(data, pivotloc + 1, high);      //遞歸
	}
}

int main(int argc, char *argv[])
{
	int data[20] = { 0, 1, 7, 3, 50, 43, 34, 78, 23, 67, 90 };  //第0個位置用於暫存pivot
	QSort(data, 1, 10);  //調用快排,對第1—10個位置上的值進行排序
	int i = 1;
	while (i <= 10)   //輸出
	{
		cout << data[i] << ' ';
		++i;
	}
	system("pause");
	return 0;
}
下面給出一個一趟快排的例子,也就是partition函數的執行過程。其中i表示low,j表示high,最右邊的49表示暫存的pivot,用於進行比較:

參考文獻:

《數據結構》,嚴蔚敏
《算法設計與分析》,王紅梅

發佈了37 篇原創文章 · 獲贊 88 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章