經典快速排序演算法與隨機快速排序演算法

2021-09-13 21:57:14 字數 2475 閱讀 3139

**:

快速排序用到了分治思想,同樣的還有歸併排序。乍看起來快速排序和歸併排序非常相似,都是將問題變小,先排序子串,最後合併。不同的是快速排序在劃分子問題的時候經過多一步處理,將劃分的兩組資料劃分為一大一小,這樣在最後合併的時候就不必像歸併排序那樣再進行比較。但也正因為如此,劃分的不定性使得快速排序的時間複雜度並不穩定。

快速排序的期望複雜度是o(nlogn),但最壞情況下可能就會變成o(n^2),最壞情況就是每次將一組資料劃分為兩組的時候,分界線都選在了邊界上,使得劃分了和沒劃分一樣,最後就變成了普通的選擇排序了。分解是將輸入陣列a[l…r]劃分成兩個子陣列的過程。選擇乙個p,使得a被劃分成三部分,分別是a[l…p-1],a[p]和a[p+1…r]。並且使得a[l…p-1]中的元素都小於等於(或大於等於)a[p],同時a[p]小於等於(或大於等於)a[p+1…r]中的所有元素。

解決是呼叫遞迴程式,解決分解中劃分生成的兩個子串行。

合併是遞迴到最深層,已經不能再劃分成更小的子串行了,便開始合併。因為在分解的時候已經比較過大小,每乙個父序列分解而來的兩個子串行不僅是有序的,而且合併成乙個序列之後還是有序的。因為快排可以在輸入陣列上進行操作,所以合併這一步不需要編寫**。

**實現:

public static void classicquicksort(int arr,int left,int right) 	}	

public static int partition(int arr, int left, int right)

} swap(arr, right, p + 1);

return p+1;

}private static void swap(int arr, int p, int i)

quicksort(int a,int left,int right)函式沒什麼好說的,設定遞迴邊界,接下來遞迴處理左序列,再處理右序列。

下來的partition(int a, int left, int right)就比較有意思了。

int x = a[right];這行**選中乙個主元,這裡我們每次選擇的都是當前序列中最右邊那個。int p = left - 1;這行**儲存了乙個變數p,用來記錄比主元小的所有元素中,在序列中存放的位置最靠右的那個。接下來是個迴圈,從當前序列的第乙個迴圈到倒數第二個(right-1)元素,來進行和主元比較。因為最後乙個已經是主元了,所以就沒有必要迴圈到right了。迴圈裡面先是乙個比較if (a[i] <= x)。這裡寫的是小於等於,更改這個就可以改變序列式由小到大還是由大到小排列。這裡則是由小到大排列。如果進入了if語句,則說明a[i](當前元素)比主元小,還記得之前的變數p嗎,儲存著比主元小的元素最右邊的位置,這裡先p++,接著把a[i]和a[p]交換,就是說把a[p]右邊的元素和當前元素換位置。a[p]右邊的元素是什麼呢?可能就是當前元素,也可能是比主元大的元素。這樣,就完成了比主元小的元素的處理。

可是如果a[i]>x呢,則不進入if執行這兩行**,也就是不動那個比主元大的元素。

這樣直到迴圈結束,整個序列就變成了三部分,從a[left…p]是比主元小的元素,a[p+1…right-1]是比主元大的元素,a[right]則是主元。而我們劃分的目的是將主元放在這兩個序列的中間,則再執行一行語句swap(a, p+1, right);,將主元和比它大序列的第乙個元素互換位置,就大功告成了。

書上的**非常的清晰:(標號是根據上面**所標,和書上不太一樣,但意思是一樣的)

這張圖描述了一次劃分。淺藍色部分是不大於主元的部分,深藍色部分是大於主元的部分。沒有顏色的是還未處理的元素,最後的元素則是主元。

快速排序的主要內容差不多就這些了,書上接下來證明了快速排序的正確性,以及計算了其時間複雜度。之後討論了劃分的不平衡性所導致的效能退化。對乙個排好序的序列使用上述快排,時間複雜度為o(n^2),而插入排序則僅為o(n)。因此便有了隨機化快速排序的出現。

快速排序的隨機化版本

上面版本的快排在選取主元的時候,每次都選取最右邊的元素。當序列為有序時,會發現劃分出來的兩個子串行乙個裡面沒有元素,而另乙個則只比原來少乙個元素。為了避免這種情況,引入乙個隨機化量來破壞這種有序狀態。

在隨機化的快排裡面,選取a[left…right]中的隨機乙個元素作為主元,然後再進行劃分,就可以得到乙個平衡的劃分。

實現起來其實只需要對上面的**做小小的修改就可以了。

public static void randomquicksort(int arr,int left,int right) 

} public static int randompartition(int arr, int left, int right)

public static void swap(int arr, int left, int right)

快速排序與隨機快速排序

實現對陣列的普通快速排序與隨機快速排序。1 實現上述兩個演算法 2 統計演算法的執行時間 3 分析效能差異,作出總結 一 快速排序 通過使用分治思想對快速排序演算法進行描述。下面對乙個典型的子陣列a p r 進行快速排序的三步分治過程 分解 陣列a p r 被劃分為兩個 可能為空 子陣列a p q ...

Java演算法之經典快速排序和隨機快速排序

package cn.itcats.sort import org.junit.test r 歸類快速排序,每次取陣列最後乙個數進行比較歸類 author fatah public class quicksort quicksort arr,0,arr.length 1 public void qu...

演算法設計 快速排序 隨機快速排序演算法

1.演算法流程 快速排序的時間複雜性分析 1.最壞情況劃分 當劃分產生的兩個子問題分別包含了n 1個元素和0個元素時,快速排序是最壞情況,假如每次遞迴呼叫,總是出現最不平衡劃分,這是最不平衡劃分。劃分操作時間複雜度為 n 則演算法執行時間的遞迴表示式為t n t n 1 t 0 n 利用代入法可以求...