1. 程式人生 > 實用技巧 >純手擼——快速排序

純手擼——快速排序

運用遞迴思想:

  • 隨機找主元(一般為第一個、中間、最後一個元素)
  • 對陣列進行分割處理,小的元素放在主元前面,大的放在後面
  • 在對小的元素部分再取主元再分割,遞迴下去(同理大的元素部分)
  • 建議:下拉看圖~

一張圖歸納我的上述思想:

重難點操作:分割 圖片參考美文——不要在問我快速排序,寫的實在太好了!

1️⃣單向調整

選一個主元,如選最後一個為主元。假設陣列arr的範圍為[left, right],即起始下標為left,末尾下標為right。源陣列如下:

然後可以用一個下標 i 指向 left,即 i = left ;用一個下標 j 也指向left,即j = left

接下來 j 從左向右遍歷,遍歷的範圍為 [left, right-1] ,遍歷的過程中,如果遇到比主元小的元素,則把該元素與 i 指向的元素交換,並且 i = i +1

如:當j指向1時,1比4小,此時把i和j指向的元素交換,之後 i++

就這樣讓j一直向右遍歷,直到 j = right

遍歷完成之後,把 i 指向的元素與主元進行交換,交換之後,i 左邊的元素一定小於主元,而 i 右邊的元素一定大於或等於主元。這樣,就 i 完成了一次分割了

有了上面的引導,一切真的非常簡單了,直接開寫吧:

int partition(int a[],int left,int right)
{
    int tmp,pivot; //tmp作為臨時儲存,pivot指向主元
    int i,j; 
    pivot=a[right]; //照著圖片寫的,主元取最後一個元素
    for(j=left;j<right;j++)
    {
    	if(a[j]<pivot)
    	{
    		//swap
    		tmp=a[i];
    		a[i]=a[j];
    		a[j]=tmp;
    		i++; //記得i要移一下喲
    	}
    }
    //i指向的元素與主元元素交換
    a[right]=a[i];
    a[i]=pivot;
    return i;
}
void QuickSort(int a[],int left ,int right)
{
 	int center;
 	//至少存在兩個元素
 	if(left<right)
 	{
 		center=partition(a,left,right);
 		QuickSort(a,left,center-1); //左區間遞迴
 		QuickSort(a,center+1,right); //右區間遞迴
 	}
}

2️⃣雙向調整

還是用我的第一個元素充當主元吧。哈哈,源陣列如下:

然後用令變數i = left + 1,j = right。然後讓 i 和 j 從陣列的兩邊向中間掃描

i 向右遍歷的過程中,如果遇到大於或等於主元的元素時,則停止移動,j向左遍歷的過程中,如果遇到小於或等於主元的元素則停止移動

當i和j都停止移動時,如果這時i < j,則交換 i, j 所指向的元素。此時 i < j,交換8和3

然後繼續向中間遍歷,直到i >= j

此時i >= j,分割結束。

最後在把主元與 j 指向的元素交換(當然,與i指向的交換也行)

這個時候,j 左邊的元素一定小於或等於主元,而右邊則大於或等於主元。

到此,分割調整完畢

有了上面的引導,一切又非常簡單了,直接開寫吧:

int partition(int a[],int left,int right)
{
	int pivot=a[left]; //這次把主元定在第一個元素
	int i=left+1; //i指向主元旁第一個元素
	int j=right;
	while(i<j) //從兩端向中間掃描,直到i=j為止
	{
		//從左向右掃描
		while(i<=j&&a[i]<=pivot) i++;
		//從右向左掃描
		while(i<=j&&a[j]>=pivot) j--;
		if(i>=j)
			break;
		//swap
		int tmp=a[i];
		a[i]=a[j];
		a[j]=tmp;
	}
	//a[j]或a[i]與主元交換
	a[left]=a[j];
	a[j]=pivot;
	return j;
}

void QuickSort(int a[],int left ,int right)
{
 	int center;
 	//至少存在兩個元素
 	if(left<right)
 	{
 		center=partition(a,left,right);
 		QuickSort(a,left,center-1); //左區間遞迴
 		QuickSort(a,center+1,right); //右區間遞迴
 	}
}

一點心得:對於這種演算法,其實如果直接讀書看程式碼或記憶真的還挺有難度,不妨記住實現的步驟圖,跟著圖自行擬出程式碼即可。