算法一直是計算機學科中一個很是核心的內容,學習大黑書可讓咱們年輕人獲得充沛的力量(也就是少點頭髮),在程序的海洋裏快樂徜徉。算法
排序算法是算法之中一個既基礎又核心的內容,而快速排序則是比較排序中的佼佼者。今天咱們就一塊兒來探究一下快速排序。segmentfault
快速排序是一個經典的分治算法,解決分治問題的三個步驟就是 分解、解決、合併。數組
拆開來看看快速排序的基本思想:dom
分解 :將輸入數組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]中的全部元素。性能
解決:遞歸調用快速排序,解決分解中劃分生成的兩個子序列的排序。學習
合併:由於子數組都是原址排序的,因此無需進行合併操做,數組A[p..r]已經有序。測試
算法導論書上給出了簡單易懂的僞代碼,我在這直接給出Python的實現代碼ui
def Quick_Sort(A,p,r): if p<r: q=Partition(A,p,r) Quick_Sort(A,p,q-1) Quick_Sort(A,q,r) def Partition(A,p,r): x=A[r] i=p-1 for j in range(p,r): if A[j]<=x: i+=1 A[i],A[j]=A[j],A[i] A[i+1],A[r]=A[r],A[i+1] return i+1
這裏看到數組的劃分是直接選擇了子數組的最後一個元素,那麼當待排序列已經有序時,劃分出的子序列便有一個序列是不含任何元素的,這使得排序的性能變差。爲了改善這種狀況,咱們能夠選擇引入一個隨機量來破壞有序狀態。spa
咱們能夠經過在選擇劃分時隨機選擇一個主元來實現隨機快速排序。僅需對上述代碼作出小小的改動。code
def Quick_Sort_Random(A,p,r): if p<r: q=Partition1(A,p,r) Quick_Sort(A,p,q-1) Quick_Sort(A,q,r) def Partition1(A,p,r): k=random.randint(p,r) A[k],A[r]=A[r],A[k] return Partition(A,p,r)
是騾子是馬咱們拉出來溜溜,我對兩種快排的性能作了一個簡單的測試。首先是必定數量的隨機序列,運行的時間單位爲秒,下表中的結果是經屢次運行所取得的平均值。
方法 | $10^3$ | $10^4$ | $10^5$ | $10^6$ | $10^7$ | 5*$10^7$ | $10^8$ |
---|---|---|---|---|---|---|---|
普通快排 | 0.00204557 | 0.02453995 | 0.32335813 | 4.83641084 | 63.91342704 | 456.20516078 | 1176.27041785 |
隨機快排 | 0.00228848 | 0.03292949 | 0.39734049 | 5.41323487 | 66.26046769 | 451.38552999 | 1108.05737074 |
也可使用可視化的方法將上表變得更加清楚,普通排序在數據量較小時具備必定的性能優點,隨機快排多是由於添加了隨機選擇這一項操做而影響了部分性能,可是隨着數據量進一步增大,二者之間的性能會很是接近。
接下來是對有序序列進行測試,
方法 | $10^3$ | $10^4$ | $10^5$ | $10^6$ |
---|---|---|---|---|
普通快排 | 0.06262696 | / | / | / |
隨機快排 | 0.03440228 | 0.45189877 | 7.28055120 | 95.54553382 |
普通快排在數據量很是小的時候就把棧給擠爆嘍,從另外一側面反映出隨機快排的必要性,在處理比較極端也就是徹底有序的序列時具備較大的優點~