【算法】算法圖解筆記_快速排序

分而治之

分而治之(divide and conquer,D&C)是一種著名的遞歸式問題解決方法。
只能解決一種問題的算法畢竟用處有限,而D&C提供瞭解決問題的思路,是另一個可供你使用的工具。

D&C算法是遞歸的。使用D&C解決問題的過程包括兩個步驟。
(1) 找出基線條件,這種條件必須儘可能簡單。
(2) 不斷將問題分解(或者說縮小規模),直到符合基線條件。

例1

假設你是農場主,有一小塊土地。如何將一塊地均勻地分成方塊,並確保分出的方塊是最大的呢?
圖片描述

基線條件

最容易處理的情況是,一條邊的長度是另一條邊的整數倍。比如,25m x 50m的土地可以分成 2 個 25m x 25m 的方塊。

遞歸條件

根據D&C的定義,每次遞歸調用都必須縮小問題的規模。首先找出這塊地可容納的最大方塊。如,上圖可以劃出兩個640 m × 640 m的方塊,同時餘下一小塊400m x 640m 地。
我們下一步要做的就是對餘下的那一小塊地使用相同的算法。因爲適用於這小塊地的最大方塊,也是適用於整塊地的最大方塊。換言之,你將均勻劃分1680 m × 640 m土地的問題,簡化成了均勻劃分400m x 640 m土地的問題!

我們很容易實現上述過程。我們進一步抽象,這個過程實際上就是求兩個整數的最大公倍數。

例2

給定一個數字數組,如,[2,4,6],怎麼返回這些數字相加後的結果。使用循環可以很容易實現。那使用遞歸怎麼實現呢?

基線條件

最簡單的數組不包含任何元素或只包含一個元素,這個可以認爲是數組的基線條件。

遞歸條件

每次遞歸調用都必須離空數組更近一步。我們通過下面的等式縮小問題的規模。
sum [2,4,6] == 2 + sum [4,6]

使用Haskell可以很容易實現:

sum [] = 0
sum (x:xs) = x + (sum xs)

快速排序

快速排序是一種常用的排序算法,如,C語言標準庫中的函數qsort實現的就是快速排序。

基線條件

數組爲空或只包含一個元素。在這種情況下,只需原樣返回數組。

遞歸條件

我們從數組中選擇一個元素作爲基準值(pivot),然後以該值爲基準對數據分區(partitioning),這樣數組劃分成了三部分:

  1. 一個由所有小於基準值的數字組成的子數組;
  2. 基準值
  3. 一個由所有大於基準值的數組組成的子數組。

這樣問題縮小到了子數組規模。再分別對子數組應用以上過程,得到排序後的子數組,最終我們只要將這三部分拼接起來就能得到完全排序的數組。

注意:爲了實現簡單,基準值每次都取的數組首元素。

代碼如下:

# python
def quicksort(array):
  if len(array) < 2:
    return array
  else:
    pivot = array[0]
    less = [i for i in array[1:] if i <= pivot]
    greater = [i for i in array[1:] if i > pivot]
    return quicksort(less) + [pivot] + quicksort(greater)
--haskell
import Data.List

quickSort :: Ord a => [a] -> [a]
quickSort [] = []
quickSort (x:xs) = quickSort lhs ++ [x] ++ quickSort rhs
  where
    (lhs, rhs) = partition (< x) xs

注意:上面的版本每次都新生成子數組,有些人認爲正確的快速排序應該使用in-place交換,所以上面的算法不“正宗”。

再談大 O 表示法

快速排序的獨特之處在於,其速度取決於選擇的基準值。在平均情況下,快速排序的運行時間爲O(nlog n),在最糟情況下,退化爲O(n2)。還有一種合併排序(merge sort)的排序算法,其運行時間爲O(nlogn)。

大O表示法體現出的是對元素規模n的增速,但處理每個元素的速度是有差異的,比如,對每個元素執行(*2)和(+3).(*2)操作,明顯是後者執行的時間長。
快速排序和合並排序的算法速度分別表示爲c1 nlogn和c2 nlogn,c是算法所需的固定時間量,被稱爲常量。通常不考慮這個常量,因爲如果兩種算法的大O運行時間不同,這種常量將無關緊要。但有時候,常量的影響可能很大,對快速查找和合並查找來說就是如此。快速查找的常量比合並查找小,因此如果它們的運行時間都爲O(n log n),快速查找的速度將更快。實際上,快速查找的速度確實更快,因爲相對於遇上最糟情況,它遇上平均情況的可能性要大得多。

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