普通快排和隨機快排的世紀大戰

file

算法一直是計算機學科中一個很是核心的內容,學習大黑書可讓咱們年輕人獲得充沛的力量(也就是少點頭髮),在程序的海洋裏快樂徜徉。算法

file

排序算法是算法之中一個既基礎又核心的內容,而快速排序則是比較排序中的佼佼者。今天咱們就一塊兒來探究一下快速排序。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

也可使用可視化的方法將上表變得更加清楚,普通排序在數據量較小時具備必定的性能優點,隨機快排多是由於添加了隨機選擇這一項操做而影響了部分性能,可是隨着數據量進一步增大,二者之間的性能會很是接近。

file

接下來是對有序序列進行測試,

方法 $10^3$ $10^4$ $10^5$ $10^6$
普通快排 0.06262696 / / /
隨機快排 0.03440228 0.45189877 7.28055120 95.54553382

普通快排在數據量很是小的時候就把棧給擠爆嘍,從另外一側面反映出隨機快排的必要性,在處理比較極端也就是徹底有序的序列時具備較大的優點~

相關文章
相關標籤/搜索