1. 程式人生 > >快速排序、程式碼實現(python3版)及其時間空間複雜度分析

快速排序、程式碼實現(python3版)及其時間空間複雜度分析

快速排序是對氣泡排序的一種改進。基本思想是:通過一躺排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按次方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。最壞情況的時間複雜度為O(n2),最好情況時間複雜度為O(nlog2n)。

import random
def position(l,beg,end):
    # 掃描指標
    index = beg
    # 換位置
    mid=l[end]
    for i in range(beg,end):
        if l[i] <= mid:
            l[index], l[i] = l[i], l[index]
            index += 1
    l[index], l[end] = l[end], l[index]
    return index

# 排序
def mysort(l,beg,end):
    if beg<=end:
    # 找到拆分元素的下標
        p = position(l,beg,end)
    # 將列表左半部分排序
        mysort(l,beg,p-1)
    # 將列表右半部分排序
        mysort(l,p+1,end)
if __name__ == '__main__':
    l = list(range(10))
    random.shuffle(l)
    print(l)
    mysort(l,0,len(l)-1)
    print(l)

時間複雜度

        快速排序涉及到遞迴呼叫,所以該演算法的時間複雜度還需要從遞迴演算法的複雜度開始說起;
       遞迴演算法的時間複雜度公式:T[n] = aT[n/b] + f(n)  ;對於遞迴演算法的時間複雜度這裡就不展開來說了;

最優情況下時間複雜度
        快速排序最優的情況就是每一次取到的元素都剛好平分整個陣列(很顯然我上面的不是);
        此時的時間複雜度公式則為:T[n] = 2T[n/2] + f(n);T[n/2]為平分後的子陣列的時間複雜度,f[n] 為平分這個陣列時所花的時間;
        下面來推算下,在最優的情況下快速排序時間複雜度的計算(用迭代法):
                                         T[n] =  2T[n/2] + n                                                                     ----------------第一次遞迴
                 令:n = n/2        =  2 { 2 T[n/4] + (n/2) }  + n                                               ----------------第二次遞迴
                                            =  2^2 T[ n/ (2^2) ] + 2n
                令:n = n/(2^2)   =  2^2  {  2 T[n/ (2^3) ]  + n/(2^2)}  +  2n                         ----------------第三次遞迴  
                                            =  2^3 T[  n/ (2^3) ]  + 3n
                ......................................................................................                        
                令:n = n/(  2^(m-1) )    =  2^m T[1]  + mn                                                  ----------------第m次遞迴(m次後結束)
               當最後平分的不能再平分時,也就是說把公式一直往下跌倒,到最後得到T[1]時,說明這個公式已經迭代完了(T[1]是常量了)。
               得到:T[n/ (2^m) ]  =  T[1]    ===>>   n = 2^m   ====>> m = logn;
               T[n] = 2^m T[1] + mn ;其中m = logn;
               T[n] = 2^(logn) T[1] + nlogn  =  n T[1] + nlogn  =  n + nlogn  ;其中n為元素個數
               又因為當n >=  2時:nlogn  >=  n  (也就是logn > 1),所以取後面的 nlogn;
               綜上所述:快速排序最優的情況下時間複雜度為:O( nlogn )

最差情況下時間複雜度

        
最差的情況就是每一次取到的元素就是陣列中最小/最大的,這種情況其實就是氣泡排序了(每一次都排好一個元素的順序)

     這種情況時間複雜度就好計算了,就是氣泡排序的時間複雜度:T[n] = n * (n-1) = n^2 + n;

     綜上所述:快速排序最差的情況下時間複雜度為:O( n^2 )

平均時間複雜度
       快速排序的平均時間複雜度也是:O(nlogn)

空間複雜度
        其實這個空間複雜度不太好計算,因為有的人使用的是非就地排序,那樣就不好計算了(因為有的人用到了輔助陣列,所以這就要計算到你的元素個數了);我就分析下就地快速排序的空間複雜度吧;
        首先就地快速排序使用的空間是O(1)的,也就是個常數級;而真正消耗空間的就是遞迴呼叫了,因為每次遞迴就要保持一些資料;
     最優的情況下空間複雜度為:O(logn)  ;每一次都平分陣列的情況
     最差的情況下空間複雜度為:O( n )      ;退化為氣泡排序的情況
     時間空間複雜度部分參考了此文https://blog.csdn.net/yuzhihui_no1/article/details/44198701