1. 程式人生 > >資料結構-排序演算法原理和Python實現

資料結構-排序演算法原理和Python實現

有些時候看懂了,不一定會寫,不妨自己寫一遍程式碼看看會有什麼收穫。

排序演算法概覽

排序演算法概覽

插入排序

基本思想是每次講一個待排序的記錄,按其關鍵字大小插入到前面已拍好的子序列中,直到全部完成。

直接插入排序

講元素L(i)插入到有序序列L[1,…,i-1]中,執行以下操作:
1. 查找出L(i)在L[1,…,i-1]中的插入位置k。
2. 將L[k,…,i-1]中所有元素全部後移一位。
3. 將L(i)複製到L(k)

def InsertSort(array_a, n):
    for i in
range(1, n): temp = array_a[i] j = i - 1 while temp < array_a[j] and j >= 0: array_a[j + 1] = array_a[j] # 如果小於其前驅,則從後往前尋找插入位置並後移。 j -= 1 array_a[j + 1] = temp return array_a

希爾排序

希爾排序的實質就是分組插入排序。
基本思想:
1. 先取一個小於n的步長d1(一般為n/2),把表分為d1個組,每個組的元素間隔個d1。
2. 在各組之內使用直接插入排序。
3. 選取第二個步長,一般為d1/2,重複上述過程,直到步長為1.

嚴格意義的希爾排序:

def ShellSort(array_a, n):
    dk = n / 2
    while dk >= 1:
        for i in xrange(0, dk):
            for j in range(i + dk, n, dk):
                temp = array_a[j]
                k = j - dk
                while temp < array_a[k] and k >= 0:
                    array_a[k + dk] = array_a[k]  # 如果小於其前驅,則從後往前尋找插入位置並後移。
k -= dk array_a[k + dk] = temp dk = dk / 2 return array_a

其實每次元素和間隔dk倍數的前驅比較,做插入排序即可,簡化版:

def ShellSort2(array_a, n):
    dk = n / 2
    while dk >= 1:
        for i in range(dk, n):
            temp = array_a[i]
            k = i - dk
            while temp < array_a[k] and k >= 0:
                array_a[k + dk] = array_a[k]  # 如果小於其前驅,則從後往前尋找插入位置並後移。
                k -= dk
            array_a[k + dk] = temp
        dk = dk / 2
    return array_a

交換排序

交換即根據序列中兩個元素比較結果來交換兩個元素的位置。

氣泡排序

  1. 對於長度為n的表,從後往前依次比較兩兩相鄰的元素值,若為逆序則交換他們的值,直到這個序列比較完,此為一趟。
  2. 下一趟減少一個排好元素,最終n-1趟排序完成。
def BubbleSort(array_a, n):
    for i in range(0, n - 1):
        flag = 0  # 交換標誌
        for j in range(n - 1, i, -1):
            if array_a[j] < array_a[j - 1]:
                temp = array_a[j]
                array_a[j] = array_a[j - 1]
                array_a[j - 1] = temp
                flag = 1
        if flag == 0:
            return array_a  # 若此趟未發生交換,說明已經有序,返回
    return array_a

快速排序

快速排序基本思想:
1. 在待排序表中任選一個元素作為pivot,以它為基準將陣列分為比它大和小的兩部分,此時pivot放在了最終的位置上。
2. 然後遞迴地對兩個子表進行上述過程
3. 直到每部分都只有一個元素或者為空為止

def QuickSort(array_a, low, high):
    if low < high:
        pivotpos = Partition(array_a, low, high)
        QuickSort(array_a, pivotpos + 1, high)
        QuickSort(array_a, low, pivotpos - 1)
    return array_a

def Partition(array_a, low, high):
    pivot = array_a[low]
    while low < high:
        while low < high and array_a[high] >= pivot:
            high -= 1
        array_a[low] = array_a[high]  # 左移比pivot小的元素
        while low < high and array_a[low] <= pivot:
            low += 1
        array_a[high] = array_a[low]  # 右移比pivot大的元素
    array_a[low] = pivot
    return low

選擇排序

基本思想:
1. 初始i=0。
2. 第i趟在後面n-i+1個元素中,選取最小的,作為第i個元素的值。
3. 一直到i=n-1做完。

簡單選擇排序

和上面思想一致,每趟找出最小值和第i個元素交換。找最小元素使用遍歷的方法:

def SelectSort(arrau_a, n):
    for i in xrange(n - 1):
        min = i
        for j in range(i + 1, n):
            if array_a[j] < array_a[min]:
                min = j
        temp = array_a[i]
        array_a[i] = array_a[min]
        array_a[min] = temp

堆排序

堆排序是一種樹形的選擇排序方法,利用二叉樹中雙親和孩子結點的關係,選擇無序區域的關鍵最大(最小)的元素。
堆定義:n個關鍵字的序列稱為堆,當且僅當其滿足:
1. L(i)≤L(2i) 且L(i)≤L(2i+1)
或者
2. L(i)≥L(2i) 且L(i)≥L(2i+1)
其中1是小根堆,2是大根堆。

堆排序關鍵是構建初始堆,直接大根堆程式碼

def BuildMaxHeap(array_a, n):
    for i in range(n / 2, 0, -1):  # 從i=[n/2-1]~0,反覆調整堆。
        AdjustDown(array_a, i, n - 1)


def AdjustDown(array_a, k, n):
    array_a[0] = array_a[k]
    i = 2 * k
    while (i <= n):  # 沿著k的子結點篩選
        if i < n:
            if array_a[i] < array_a[i + 1]:
                i += 1  # 取值更大的子結點
        if array_a[0] > array_a[i]:
            break
        else:
            array_a[k] = array_a[i]  # array_a[i]調整到雙親上。
            k = i
        i *= 2
        array_a[k] = array_a[0]  # 被篩選的點放入最終位置。


def HeapSort(array_a, n):
    array_a.insert(0, 0)  # 首先array_a所有元素後移,rray_a[0]不存放元素
    n = len(array_a)
    BuildMaxHeap(array_a, n)
    for i in range(n - 1, 1, -1):
        temp = array_a[i]
        array_a[i] = array_a[1]
        array_a[1] = temp  # 將最大的元素放在當前無序陣列的最後
        AdjustDown(array_a, 1, i - 1)  # 把剩餘的i-1整理成堆。

歸併排序

歸併排序是將兩個或者以上的有序表組成新的有序表。下面以二路歸併為例:
遞迴實現:
1. 先把待排序區間[s,t]以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間[s,t]。
2. 合併兩個有序陣列:
1. 陣列比較a[i]和a[j]的大小。
1. 若a[i]≤a[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;
2. 否則將第二個有序表中的元素a[j]複製到r[k]中,並令j和k分別加上1。
2. 如此迴圈下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。

def Merge(array_a, low, mid, high):
    # 合併array_a的[low,...mid]和[mid+1,...high]的各自有序的兩部分為一個新的有序表
    b = []
    for each in array_a[low:high + 1]:
        b.append(each)  # 將序列儲存到b中。
    i, j = low, mid + 1  # 其實i,j就是標記兩個表比較到的位置。
    k = i
    while i <= mid and j <= high:
        # 將較小的元素一個加入到陣列array_a中。
        if b[i - low] <= b[j - low]:
            array_a[k] = b[i - low]
            i += 1
        else:
            array_a[k] = b[j - low]
            j += 1
        k += 1
    # 如果兩個表有一個沒有檢測完,則複製。
    while i <= mid:
        array_a[k] = b[i - low]
        k += 1
        i += 1
    while j <= high:
        array_a[k] = b[j - low]
        k += 1
        j += 1


def MergeSort(array_a, low, high):
    if low < high:
        mid = (low + high) / 2  # 劃分為兩個子序列。
        MergeSort(array_a, low, mid)  # 分別對子序列遞迴排序。
        MergeSort(array_a, mid + 1, high)
        Merge(array_a, low, mid, high)  # 合併左右兩個有序的子序列。

基數排序

基數排序並不是基於比較敗絮,而是採用多關鍵字排序思想,即基於關鍵字的各位大小排序,分為最高位有限和最低位優先排序。