1. 程式人生 > >常見排序算法之python實現

常見排序算法之python實現

uic 位置 cti gte https 最大值 ice 插入排序 快速

  本文介紹了幾種常用的排序算法,包含冒泡排序,選擇排序,插入排序,歸並排序,快速排序,堆排序,本文涉及的代碼可以在https://github.com/lianyingteng/Programming-practice上找到

1. 冒泡排序

時間復雜度為O(n^2), 穩定的排序算法

思路:一開始比較的區間是【0,n-1】,依次比較相鄰兩數,哪個數大哪個數就放在後面,這樣一次遍歷數組後,最大的數會在數組的最後一個位置,然後比較區間從【0,n-1】縮小到了【0,n-2】,在進行一次遍歷下來,第二大的數會被放在數組倒數第二的位置,依次類推。直到把範圍縮小到一個數的時候,數組就有序了。

def bubbleSort(arr):

  length
= len(arr) for i in range(length-1): #趟數 for j in range(length-i-1): #每趟元素數 if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr

2. 選擇排序

時間復雜度為O(n^2),不穩定的排序算法

思路:一開始從【0,n-1】選出一個最小值放在位置0上;第二次從【1,n-1】上選擇一個最小值放在位置1上;依次類推;直到數組訪問剩下一個元素時,數組有序了。

def selectionSort(arr):
    """選擇排序
    """
    length = len(arr)

    for i in range(length):
        min_i = i # 最小值索引
        for j in range(i, length):
            if arr[min_i] > arr[j]:
                min_i = j

        arr[min_i], arr[i] = arr[i], arr[min_i]

    return arr

3. 插入排序*

時間復雜度為O(n^2),穩定的排序算法

:當數組幾乎有序的情況下,時間復雜度為O(n*k),k為最多移動的距離;當數組逆序時,時間復雜度最大為O(n^2)

思路:把n個待排序的元素看成是一個有序表和一個無序表,開始時有序表只有一個元素,無序表有n-1個元素。排序過程中每次從無序表中取出一個元素,把它的排序碼依次與有序表中元素比較(後->前),將它插入有序表的適當位置,使之成為新的有序表。

def insertSort(arr):
    """插入排序
    """
    length = len(arr)

    for i in range(length-1):
        o_i = i # 有序表最後一個元素索引
        u_v = arr[o_i+1] # 無序表的元素值
        
        while o_i >= 0 and arr[o_i] > u_v:
            arr[o_i+1] = arr[o_i]
            o_i -= 1
        arr[o_i+1] = u_v # 帶插入元素合適位置,+1是因為前面-1

    return arr

4. 歸並排序*

時間復雜度為O(nlogn),穩定的排序算法

思路:首先讓數組每一個元素成為長度為1的有序區間;然後將兩個長度為1的有序區間進行合並,生成長度為2的有序區間;然後再將兩個長度為2的有序區間進行合並,生成長度為4的有序區間;依次類推,直至數組有序。1合2,2合4,4合8,8合16,……

def mergerSort(arr):
    """歸並排序

        劃分成左右兩部分; 兩兩合並,成有序數組
    """
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    # 左右劃分, 生成長度為1的有序數組時開始返回
    leftArr = mergerSort(arr[:mid])
    rightArr = mergerSort(arr[mid:])
    # 兩兩合並
    return merger(leftArr, rightArr)

def merger(left, right):
    """合並兩個有序數組,形成新的有序數組返回
    """
    res = []
    l, r = 0, 0
    while l < len(left) and r < len(right):
        if left[l] <= right[r]:
            res.append(left[l])
            l += 1
        else:
            res.append(right[r])
            r += 1

    res += left[l:]
    res += right[r:]
    return res

5. 快速排序**

時間復雜度為O(nlogn), 不穩定的排序算法

:在數組完全無序的情況下,快排效果最好,為O(nlogn);在有序情況下效果最差,為O(n^2)。

思路:隨機排序 - 在數組中隨機選擇一個數,使得數組中大於它的數放在它的右邊、小於等於它的數放在它的左邊,然後左右兩邊的數遞歸的調用快排的過程。

快排的一次劃分過程  -  時間復雜度為O(n):

  首先,我們隨機選擇數組中的一個作為劃分值;然後把劃分值與數組的最後一個元素進行交換,使得劃分值放到數組的最後一個位置(如b);然後我們定義一個小於等於區間,初始時,小於等於區間為空,放在數組的最左邊(如c);然後開始遍歷數組,如果元素大於劃分值,繼續遍歷下一個元素,如果元素值小於等於劃分值,就讓該元素與小於等於區間的下一個元素進行交換,擴增小於等於區間(如d,e);依次執行這個過程,直到數組中只剩一個數;然後數組最後一個數(劃分值)與小於等於區間的下一個數進行交換,快排的一次劃分過程就結束了(如f,g)。

     技術分享

def quickSort(arr, left, right):
    """快速排序

        對left到right區間上的數組進行快排
    """
    if left >= right:
        return None

    midValue = arr[(left+right)//2] # 劃分值
    l, r = left, right
    while l < r:
        while arr[l] < midValue: l += 1
        while arr[r] > midValue: r -= 1

        if l >= r: break

        arr[l], arr[r] = arr[r], arr[l]
        r -= 1
        l += 1

    if l == r:
        l += 1
        r -= 1

    if left < r: quickSort(arr, left, r)
    if right > l: quickSort(arr, l, right)

    return None

6. 堆排序

時間復雜度:O(nlogn),不穩定的排序算法,常用於查找top x

思路:首先將數組【0,n-1】區間上的所有元素構建大根堆,然後將堆頂元素與數組最後一個元素進行交換,這樣數組最後一個元素為最大值,作為數組有序部分存在下來;然後將數組【0,n-2】區間上的所有元素構建大根堆,然後執行堆頂元素與數組的倒數第二個元素進行交換,這樣數組後兩位元素分別是數組的最大值和第二大的值存在下來;然後將數組區間【0,n-3】區間構建大根堆,交換;重復以上過程直到數組有序。

def heapSort(arr):
    """堆排序
    """
    arr = buildMaxHeap(arr)

    for i in list(range(len(arr)))[::-1]:
        arr[0], arr[i] = arr[i], arr[0]
        adjustHeap(arr, 0, i) # n表示數組的大小(不是堆)

    return arr

def buildMaxHeap(arr):
    """建立大根堆

        從下向上構建
    """
    for i in list(range(len(arr)//2))[::-1]:
        adjustHeap(arr, i, len(arr))

    return arr

def adjustHeap(arr, start, size):
    """將數組[start:]調整成堆結構

        參數
        ---
            start: int
                數組起始index
            size:int
                數組大小
    """
    lChild = 2 * start + 1
    rChild = 2 * start + 2

    maxi = start

    if maxi < size//2: # 說明有孩子
        if lChild < size and arr[lChild] > arr[maxi]:
            maxi = lChild
        if rChild < size and arr[rChild] > arr[maxi]:
            maxi = rChild

        if maxi != start: # == 說明已經是最大堆了,所以這裏不是
            arr[maxi], arr[start] = arr[start], arr[maxi]
            adjustHeap(arr, maxi, size)

常見排序算法之python實現