排序算法-快速排序(三種實現方案)

一、快速排序算法(一)

說明

      快速排序法(quick sort)是目前所公認最快的排序方法之一(視解題的對象而定),雖然快速排序法在最差狀況下可以達O(n2),但是在多數的情況下,快速排序法的效率表現是相當不錯的。
      快速排序法的基本精神是在數列中找出適當的軸心,然後將數列一分爲二,分別對左邊與右邊數列進行排序,而影響快速排序法效率的正是軸心的選擇。
      這裏所介紹的第一個快速排序法版本,是在多數的教科書上所提及的版本,因爲它最容易理解,也最符合軸心分割與左右進行排序的概念,適合對初學者進行講解。

解法

      這裏所介紹的快速演算如下:將最左邊的數設定爲軸,並記錄其值爲s
      迴圈處理:
            令索引i 從數列左方往右方找,直到找到大於s 的數
            令索引j 從數列左右方往左方找,直到找到小於s 的數
            如果i >= j,則離開回圈
            如果i < j,則交換索引i與j兩處的值
            將左側的軸與j 進行交換
            對軸左邊進行遞歸

            對軸右邊進行遞迴

通過以下演算法,則軸左邊的值都會小於s,軸右邊的值都會大於s,如此再對軸左右兩邊進行遞歸,就可以對完成排序的目的,例如下面的實例,*表示要交換的數,[]表示軸:
[41] 24 76* 11 45 64 21 69 19 36*
[41] 24 36 11 45* 64 21 69 19* 76
[41] 24 36 11 19 64* 21* 69 45 76
[41] 24 36 11 19 21 64 69 45 76
21 24 36 11 19 [41] 64 69 45 76
在上面的例子中,41左邊的值都比它小,而右邊的值都比它大,如此左右再進行遞迴至排序完成。

代碼:

<pre name="code" class="cpp">
void QuickSort_v1(int arr[], int left, int right)
{
   if(left >= right) return;
   int n = right - left +1;
   int s = arr[left];
   int i = left;
   int j = right +1 ;
   while (1) {
       while(i<right && arr[++i] < s) ;
       while(j>left && arr[--j] > s);
       if(i >= j)
           break;
       swap(arr[i], arr[j]);
   }
   if(left != j){
    arr[left] = arr[j];
    arr[j] = s;
   }
   QuickSort_v1(arr, left, j-1);
   QuickSort_v1(arr, j+1, right);
}




 

二、快速排序算法(二)

說明

      在快速排序法(一)中,每次將最左邊的元素設爲軸,而之前曾經說過,快速排序法的加速在於軸的選擇,在這個例子中,只將軸設定爲中間的元素,依這個元素作基準進行比較,這可以增加快速排序法的效率。

解法

      在這個例子中,取中間的元素s作比較,同樣的先得右找比s大的索引i,然後找比s小的索引j,只要兩邊的索引還沒有交會,就交換i 與j 的元素值,這次不用再進行軸的交換了,因爲在尋找交換的過程中,軸位置的元素也會參與交換的動作,例如:                                          41 24 76 11 45 64 21 69 19 36      首先left爲0,right爲9,(left+right)/2 = 4(取整數的商),所以軸爲索引4的位置,比較的元素是45,您往右找比45大的,往左找比45小的進行交換:                   41 24 76* 11 [45] 64 21 69 19 *36                   41 24 36 11 45* 64 21 69 19* 76                   41 24 36 11 19 64* 21* 69 45 76                   [41 24 36 11 19 21] [64 69 45 76]      完成以上之後,再初別對左邊括號與右邊括號的部份進行遞迴,如此就可以完成排序的目的。

代碼:

//取軸爲最中間元素,無需進行軸的交換,因爲在尋找交換的過程中,軸位置的元素也會參與交換中
<pre name="code" class="cpp">
void QuickSort_v2 (int arr[], int left, int right)
{
    if (left >= right ) return;
    int s = arr[(left+right)/2];
    int i = left - 1;
    int j = right +1 ;
    while(1) {
        while (i < right && arr[++i] < s);
        while (j > left && arr[--j] > s);
        if(i >= j) break;
        swap(arr[i], arr[j]);
    }
    QuickSort_v2(arr, left, j);
    QuickSort_v2(arr, j+1, right);
}



 

三、快速排序算法(三)

說明
      之前說過軸的選擇是快速排序法的效率關鍵之一,在這邊的快速排序法的軸選擇方式更加快了快速排序法的效率,它是來自演算法名書Introduction to Algorithms 之中。
解法
      先說明這個快速排序法的概念,它以最右邊的值s作比較的標準,將整個數列分爲三個部份,一個是小於s的部份,一個是大於s的部份,一個是未處理的部份,如下所示:

 

     在排序的過程中,i 與j 都會不斷的往右進行比較與交換,最後數列會變爲以下的狀態:

 

      然後將s的值置於中間,接下來就以相同的步驟會左右兩邊的數列進行排序的動作,如下所示:

 

      整個演算的過程,直接摘錄書中的虛擬碼來作說明:

<span style="font-size:18px;">QUICKSORT(A, p, r)
	if p < r
		then q <- PARTITION(A, p, r)
		QUICKSORT(A, p, q-1)
		QUICKSORT(A, q+1, r)
end QUICKSORT
PARTITION(A, p, r)
	x <- A[r]
	i <- p-1
	for j <- p to r-1
		do if A[j] <= x
			then i <- i+1
				exchange A[i]<->A[j]
	exchange A[i+1]<->A[r]
	return i+1
end PARTITION</span>

     一個實際例子的演算如下所示:

 

 

代碼:

//這個快速排序法的概念,它以最右邊的值s作比較的標準,將整個數列分爲三個部份,
//一個是小於s的部份,一個是大於s的部份,一個是未處理的部份

int partition(int number[],int left, int right) //尋找軸所在的正確位置
{
	int i,j,s;
	int temp;
	s = number[right];
	i = left - 1;
	j = left;
	for(j=left;j<right;++j)
	{
		if(number[j] <= s)
		{
			++i;
			temp = number[i];
			number[i] = number[j];
			number[j] = temp;
		}
	}
	temp = number[i+1];
	number[i+1] = number[right];
	number[right] = temp;

	return i+1;
}

void quicksort3(int number[], int left, int right)
{
	int q;
	if(left < right)
	{
		q = partition(number,left,right);
		quicksort3(number,left,q-1);
		quicksort3(number,q+1,right);
	}
}


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章