排序算法(二) 快速排序

一、什麼是快速排序?

       快速排序是對冒泡排序的改進,本質上都是通過交換兩個元素來消除逆序。

       在冒泡排序中,由於掃描過程中只對相鄰的兩個元素進行比較,因此在互換兩個相鄰元素時只能消除一個逆序

       而在快速排序中,能通過兩個不相鄰的元素的交換,消除待排序記錄中的多個逆序,則速度較冒泡排序有極大的提高。


二、快速排序實現算法思路:

     (1)、快速排序算法是一個遞歸過程:

                  一個問題能通過遞歸來解決,則說明其能夠將一個大問題分解爲無數個小問題;而且這些小問題的解決算

           法與大問題的解決算法是一毛一樣的,只是問題規模的差別。

                  所以快速排序可以分解爲無數的小問題,每一個小問題的解決方法都一樣。

     (2)、那麼這個解決方法是什麼呢?

                  首先在待排序記錄中找一個支柱元素結點(一般都是找序列的第一個元素,因爲簡單),使用這個支柱結

           點將序列劃分爲兩個子序列。

                   怎麼劃分呢?   將大於等於支柱結點值的元素放到支柱結點的右邊(子序列1);將小於支柱結點值得元

           素放到支柱結點的左邊(子序列2);然後理所應當這個支柱結點就在兩個子序列的交接點上。在此時,我們

           如果把整個序列看成三個元素:子序列2  <  支柱結點  <  子序列1,是不是有序的呢?

        (3)、理解了這一點,就好辦了!

                  我們把一個最開始的大序列通過支柱結點劃分爲兩個子序列,再將每個子序列劃分爲兩個子子序列。。。

           當所有的子序列的長度爲0 或 1 時,而且經過(2)步驟的元素交換後。那麼當前整個序列就已經是一個有序

           序列了。


          下圖爲一次劃分實例:

 

                            


     (4)、我們來詳細描述一下每一次劃分過程的交換算法(一趟快速排序)


               <1>. 將序列的第一個元素用變量x保存(則下標爲0的元素位置空下來了),用low 和 high兩個下標變量來存

                  儲序列兩端的下標。其中low是序列左端下標(下標爲 0),high爲序列的右端下標(下標爲序列長度- 1)

                  , low  <  high ;


               <2>. 因爲low位置是空的,所以可以放一個元素;因爲是左端空了,所以從右端由 high 從右端向左端遞減尋

                  找比支柱結點 x 值小的元素放入 low 的位置,low下標向後挪一個位置(low++)。然後是 high位置空了。


               <3>. 因爲high位置是空的,所以可以放一個元素;因爲是右端空了,所以從左端由 low 從左端向右端遞增尋

                  找比支柱結點 x 值大的元素放入 high的位置,high下標向前挪一個位置 (high--)。然後又是 low 位置空

                  了。    由此轉去循環執行<2>、<3>過程。直到 low < high 條件不在被滿足,退出循環。


               <4>. 將支柱結點的值保存在low = high 的下標位置。


               <5>. 一趟排序完成。


源代碼:


#include <stdio.h>

/*
**功能: 進行一趟快速排序
**參數說明:
**@record : 子序列數組;  @low : 序列左端下標;  @high : 序列右端下標
**返回值 :  支柱結點下標
*/
int QKPass(int record[], int low, int high)
{
	int x = record[low];   //保存支柱結點值

	while (low < high)
	{
	   /*
		*      因爲low位置是空的,所以可以放一個元素;因爲是左端空了,所以從右端由
		*  high 從右端向左端遞減尋找比支柱結點 x 值小的元素放入 low 的位置,low下
		*  標向後挪一個位置(low++)
		*/
		while (low < high && record[high] >= x)
		{
			high--;
		}
		if (low < high)
		{
			record[low] = record[high];
			low++;
		}

	   /*
		*      經過上面操作後,high位置是空的,所以可以放一個元素;因爲是右端空了,
		*  所以從左端由low 從左端向右端遞增尋找比支柱結點 x 值大的元素放入 high的
		*  位置,high下標向前挪一個位置 (high--)。
		*/
		while (low < high && record[low] < x)
		{
			low++;
		}
		if (low < high)
		{
			record[high] = record[low];
			high--;
		}
	}

	record[low] = x;   //將支柱結點的值保存在low = high的位置
}

/*
**功能: 快速排序入口點
**參數說明: 
**@record : 記錄序列數組;  @low : 序列左端下標;  @high : 序列右端下標
**返回值 : 無
*/
void QKSort(int record[], int low, int high)
{
	if (low < high)
	{
		int position;   //保存支柱結點下標

		position = QKPass(record, low, high);  //進行一趟快速排序,找到支柱結點的下標
		QKSort(record, low, position - 1);  //對序列2進行快速排序
		QKSort(record, position + 1, high); //對序列1進行快速排序
	}
}


int main(void)
{
	int record[] = { 48,62,35,77,55,14,35,98 };
	int len = sizeof(record) / sizeof(record[0]);
	int i = 0;

	printf("排序前: \n");
	for (i = 0;i < len;i++)
	{
		printf("%d  ", record[i]);
	}
	puts("");

	QKSort(record, 0, len - 1);

	printf("排序後: \n");
	for (i = 0;i < len;i++)
	{
		printf("%d  ", record[i]);
	}
	puts("");

	return 0;
}

運行截圖:
                                                            

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