Python經典排序算法


https://www.cnblogs.com/onepixel/p/7674659.html這個文章很nice

https://www.bilibili.com/video/av685670?from=search&seid=1637373535603658338這個動圖優秀

https://www.icourse163.org/course/ZJU-93001   MOOC浙大 數據結構 陳越、何欽銘

VisuAlgo - visualising data structures and algorithms through animation    數據結構與算法的可視化網站  更容易讓人感性理解各種算法


冒泡排序、選擇排序、插入排序這三個是最慢也是最經典的三個排序算法

快速排序對於大的亂數串列一般相信是最快的已知排序

冒泡排序 bubble sort

最簡單的排序算法,也是效率最差的,因為它必須在最終位置知道前交換,浪費許多“交換操作”

如果列表已經排序,則是最好情況,遍歷期間無需交換,如果發現已經排序,可以提前終止,這種修改下的冒泡通常稱為短冒泡排序


時間復雜度: 平均O(n^2)    最差O(n^2)     最好O(n)

空間復雜度:O(1)

穩定

#測試輸入數組
alist = [27, 33, 28, 4, 2, 26, 13, 35, 8, 14]

#冒泡排序
for i in range(len(alist)-1):
    for j in range(len(alist)-1-i):
        if alist[j] > alist[j+1]:
            alist[j],alist[j+1] = alist[j+1],alist[j]
        
#排序結果輸出
print('sorted:',alist)

選擇排序 selection sort

選擇排序改進了冒泡排序,每次遍歷列表只做一次交換


時間復雜度:平均O(n^2)    最差O(n^2)    最好O(n^2)

空間復雜度:O(1)

不穩定

#測試輸入數組
alist = [27, 33, 28, 4, 2, 26, 13, 35, 8, 14]

#選擇排序
for i in range(len(alist)-1):
    least = i
    for j in range(i+1,len(alist)):
        if alist[j] < alist[least]:
            least = j
    if least != i:
        alist[least],alist[i] = alist[i],alist[least]

#排序結果輸出
print('sorted:',alist)

插入排序 insertion sort

它始終在列表的較低位置維護一個排序的子列表,然后將每個新項 “插入” 回先前的子列表,使得排序的子列表成為較大的一個項


時間復雜度: 平均O(n^2)    最差O(n^2)     最好O(n)

空間復雜度:O(1)

穩定

#測試輸入數組
alist = [27, 33, 28, 4, 2, 26, 13, 35, 8, 14]

#插入排序
for i in range(1,len(alist)):
    j = i;
    while j>0 and alist[j-1]>alist[j]:
        alist[j-1],alist[j] = alist[j],alist[j-1]
        j -= 1
        
#排序結果輸出
print('sorted:',alist)

希爾排序 shell sort

是1959年Shell發明,第一個突破O(n^2)的排序,是對簡單插入排序的改進,與插入排序不同的是它優先比較距離較遠的元素,又叫“遞減增量排序”

是針對插入排序以下2特點改進:在對幾乎已經排好序的數據操作時,效率高,即可以達到線性排序的效率;一般來說是低效的,因為插入排序每次只能將數據移動一位

希爾排序通過將比較的全部元素分為幾個區域來提升插入排序的性能。這樣可以讓一個元素可以一次性地朝最終位置前進一大步

gap概念,gap遞減,最后一步就是插入排序,但是此時幾乎已經排好序了

gap是希爾排序核心

出名的gap設置Marcin Ciura's gap sequence ,gaps = [701, 301, 132, 57, 23, 10, 4, 1],不過下面例子用數組長度不斷整除2得到的序列作為gaps


時間復雜度:平均O(n(logn)^2)    最差O(n^2)    最好O(n)

空間復雜度:O(1)

不穩定

#測試輸入數組
alist = [27, 33, 28, 4, 2, 26, 13, 35, 8, 14]

#希爾排序
gap = len(alist)//2
while gap>0:
    #對每個gap做插入排序
    for i in range(gap,len(alist)):
        j = i
        while j>=gap and alist[j-gap]>alist[j]:
            alist[j-gap],alist[j] = alist[j],alist[j-gap]
            j -= gap           
    gap = gap//2

#排序結果輸出
print('sorted:',alist)

歸並排序 merge sort

分而治之的策略來提高性能,是分治法的典型應用

歸並排序是一種遞歸算法,不斷將列表拆分為一半

二路歸並 多路歸並

缺點是在合並過程需要額外存儲空間


時間復雜度: 平均O(nlogn)    最差O(nlogn)      最好O(nlogn)

空間復雜度:O(n)

穩定

#測試輸入數組
alist = [27, 33, 28, 4, 2, 26, 13, 35, 8, 14]

#歸並排序
def merge_sort(ilist):   
    def merge(left, right):
        result = []
        while left and right:
            result.append((left if left[0] <= right[0] else right).pop(0))
        return result + left + right
    
    if len(ilist) <= 1:
        return ilist
    mid = len(ilist) // 2
    return merge(merge_sort(ilist[:mid]), merge_sort(ilist[mid:]))

#排序結果輸出
print('sorted:',merge_sort(alist))

快速排序 quick sort

與歸並排序相同,采用分治法,而不使用額外存儲

是對冒泡排序的改進

通常明顯比其他算法更快,因為它的內部循環可以在大部分的架構上很有效的達成

簡單的版本和歸並排序一樣不好,需要額外存儲空間,但是可以改為in-place版本,也就不要額外空間了


時間復雜度: 平均O(nlogn)    最差O(n^2)      最好O(nlogn)

空間復雜度:O(nlogn)

不穩定

#測試輸入數組
alist = [27, 33, 28, 4, 2, 26, 13, 35, 8, 14]

#快速排序
def quick_sort(ilist): 
    length = len(ilist)
    if length <= 1:
        return ilist
    else:
        # Use the last element as the first pivot
        pivot = ilist.pop()
        # Put elements greater than pivot in greater list
        # Put elements lesser than pivot in lesser list
        greater, lesser = [], []
        for element in ilist:
            if element > pivot:
                greater.append(element)
            else:
                lesser.append(element)
        return quick_sort(lesser) + [pivot] + quick_sort(greater)

#排序結果輸出
print('sorted:',quick_sort(alist))

堆排序 heap sort

是對選擇排序的一種改進

利用堆這種數據結構所設計的算法 近似完全二叉樹

堆通常通過一維數組實  大根堆  小根堆


時間復雜度:平均O(nlogn)    最差O(nlogn)      最好O(nlogn)

空間復雜度:O(1)

不穩定

#測試輸入數組
alist = [27, 33, 28, 4, 2, 26, 13, 35, 8, 14]

#堆排序
def heapify(unsorted, index, heap_size):
    largest = index
    left_index = 2 * index + 1
    right_index = 2 * index + 2
    if left_index < heap_size and unsorted[left_index] > unsorted[largest]:
        largest = left_index

    if right_index < heap_size and unsorted[right_index] > unsorted[largest]:
        largest = right_index

    if largest != index:
        unsorted[largest], unsorted[index] = unsorted[index], unsorted[largest]
        heapify(unsorted, largest, heap_size)
        
def heap_sort(unsorted):
    n = len(unsorted)
    for i in range(n // 2 - 1, -1, -1):
        heapify(unsorted, i, n)
    for i in range(n - 1, 0, -1):
        unsorted[0], unsorted[i] = unsorted[i], unsorted[0]
        heapify(unsorted, 0, i)
    return unsorted

#排序結果輸出
print('sorted:',heap_sort(alist))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM