排序算法(選擇,冒泡,插入,快速,歸併,希爾,堆排,基數)(python實現)

1.選擇排序:

選擇法思路:先取一個元素進行與其後面的元素對比,如果後面的數據與這個數據的規律不符合,則記錄這個數據的位置,繼續對比,直到數據完畢,交換數據。


def select_sort(alist):
    for i in range(len(alist)-1):
        for j in range(i+1,len(alist)):
            if alist[i]>alist[j]:
                alist[i],alist[j]=alist[j],alist[i]
alist=[23,4,3,5,67,32,7,24]
select_sort(alist)
print(alist)

2.冒泡排序

冒泡排序原理: 每一趟只能將一個數歸位, 如果有n個數進行排序,只需將n-1個數歸位, 也就是說要進行n-1趟操作(已經歸位的數不用再比較)。

def bubble_sort(alist):
    # 遍歷所有數組元素
    for i in range(len(alist)):
        for j in range(0, len(alist) - i - 1):
            if alist[j]>alist[j+1]:
                alist[j],alist[j+1]=alist[j+1],alist[j]
alist=[23,4,3,5,67,32,7,24]
bubble_sort(alist)
print(alist)

3.插入排序

具體實現步驟爲:首先我們把整個數組拆分爲有序區間和未排序區間,有序區間在插入排序一開始只有一個元素,就是數組的第一個元素。接在有序區間之後的一個元素就是準備插入的元素,在圖中就是標爲綠色的元素,在有序區間內尋找位置並插入。其尋找邏輯爲:從後往前依次進行比較,如果待插入元素大於當前元素,則將待插入元素插入到當前元素的後一位,如果待插入元素小於當前元素,則將當前元素後移一位。不斷重複該過程直至到數組的最後一位。

def insertion_sort(alist):
    # 遍歷所有數組元素
    for i in range(1,len(alist)):
        key=alist[i]
        j=i-1
        while j>=0:
            if alist[j] >key:
                alist[j+1] = alist[j]
                j-=1
            else:
                break
        alist[j+1]=key
        i+=1
alist=[23,4,3,5,67,32,7,24]
insertion_sort(alist)
print(alist)

4.快速排序:

思想:先從待排序的數組中找出一個數作爲基準數,然後將原來的數組劃分成兩部分:小於基準數的左子數組和大於等於基準數的右子數組。然後對這兩個子數組再遞歸重複上述過程,直到兩個子數組的所有數都分別有序。最後返回“左子數組” + “基準數” + “右子數組”,即是最終排序好的數組。

def quick_sort(alist, start, end):
    if start >= end:
        return
    mid = alist[start]
    left = start
    right = end
    # left與right未重合,就向中間移動
    while left < right:
        while left < right and alist[right] >= mid:
            right -= 1
        alist[left] = alist[right]
        while left < right and alist[left] < mid:
            left += 1
        alist[right] = alist[left]
    # 從循環退出後,left與right相遇,即left==right
    alist[left] = mid
    # 對左邊部分執行快速排序
    quick_sort(alist, start, left-1)
    # 對右邊部分執行快速排序
    quick_sort(alist, left+1, end)
 
alist = [23,4,3,5,67,32,7,24]
quick_sort(alist, 0, len(alist) - 1)
print(alist)

【注】:

1.快速排序算法的平均時間複雜度爲O(nlogn),通常認爲在所有同數量級的排序算法中,快速排序的平均性能是最好的,這也是它被稱爲“快速排序”的原因。

2.快速排序算法相比於其他排序算法來說比較耗費空間資源,因爲快速排序需要棧空間來實現遞歸。

3.快速排序的基準元素的選取非常重要,如果基準元素選取不當,可能影響排序過程的時間複雜度和空間複雜度。爲了避免快速排序退化爲冒泡排序以及遞歸棧過深等問題,通常依照“三者取中”的法則來選取基準元素。三者取中法是指在當前待排序的子序列中,將其首元素、尾元素和中間元素進行比較,在三者中取中值作爲本趟排序的基準元素。


5.歸併排序:

思想:先遞歸分解數組,再合併數組

原理:將數組分解最小之後,然後合併兩個有序數組,基本思想是比較兩個數組的最前面的數,誰小就取誰,取完後,將相應的指針後移以爲。然後再比較,直到一個數組爲空,最後把另一個數組的剩餘部分複製過來即可。

def merge_sort(alist):
    if len(alist) <= 1:
        return alist
    # 二分分解
    num = len(alist) // 2
    left = merge_sort(alist[:num])
    right = merge_sort(alist[num:])
    # 合併
    return merge(left, right)
def merge(left, right):
    '''合併操作,將兩個有序數組left[]和right[]合併成一個大的有序數組'''
    # left與right的下標指針
    l, r = 0, 0
    result = []
    while l < len(left) and r < len(right):
        if left[l] < right[r]:
            result.append(left[l])
            l += 1
        else:
            result.append(right[r])
            r += 1
    result += left[l:]
    result += right[r:]
    return result
alist = [23,4,3,5,67,32,7,24]
sorted_alist = merge_sort(alist)
print(sorted_alist)

6.希爾排序:

 

def shellSort(alist):
    # 設定步長
    step = len(alist)//2
    while step > 0:
        for i in range(step, len(alist)):
            # 類似插入排序, 當前值與指定步長之前的值比較, 符合條件則交換位置
            while i >= step and alist[i-step] > alist[i]:
                alist[i], alist[i-step] = alist[i-step], alist[i]
                i -= step
        step = step//2
    return alist
alist = [23,4,3,5,67,32,7,24]
shellSort(alist)
print(shellSort(alist))

7.堆排序

思想:堆排序是簡單選擇排序的改進算法,簡單選擇排序在待排序的個數據中選擇一個最小的元素需要進行n-1次的比較,但是並沒有將每一次循環的結果保存下來,在下一次循環中,有很多比較已經在上一次的循環中做過了,但由於上一次循環時沒有保存這些比較結果,所以下一次循環時又要重複這些比較操作,因此數據的比較次數較多。堆排序可以做到每次在選擇最小記錄的同時,根據比較結果對其他元素做出相應的調整。
 

堆的特點就是FIFO(first in first out)先進先出,這裏的話我覺得可以理解成樹的結構。 
堆在接收數據的時候先接收的數據會被先彈出。

棧的特性正好與堆相反,是屬於FILO(first in/last out)先進後出的類型。 
棧處於一級緩存而堆處於二級緩存中。這個不是本文重點所以不做過多展開。

堆(定義):(二叉)堆數據結構是一個數組對象,可以視爲一棵完全二叉樹。如果根結點的值大於(小於)其它所有結點,並且它的左右子樹也滿足這樣的性質,那麼這個堆就是大(小)根堆。
 

def build_heap(alist):
    """建立一個堆"""
    # 自底向上建堆
    for i in range(len(alist) //2 - 1, -1, -1):
        heap(alist, len(alist), i)
def heap(alist, heap_size, index):
    """調整列表中的元素以保證以index爲根的堆是一個最大堆"""

    # 將當前結點與其左右子節點比較,將較大的結點與當前結點交換,然後遞歸地調整子樹
    left_child = 2 * index + 1
    right_child = left_child + 1
    if left_child < heap_size and alist[left_child] > alist[index]:
        largest = left_child
    else:
        largest = index
    if right_child < heap_size and alist[right_child] > alist[largest]:
        largest = right_child
    if largest != index:
        alist[index], alist[largest] = alist[largest], alist[index]
        heap(alist, heap_size, largest)
def heapsort(alist):
    """堆排序"""
    # 先將列表調整爲堆
    build_heap(alist)
    heap_size = len(alist)
    # 調整後列表的第一個元素就是這個列表中最大的元素,將其與最後一個元素交換,然後將剩餘的列表再調整爲最大堆
    for i in range(len(alist) - 1, 0, -1):
        alist[i], alist[0] = alist[0], alist[i]
        heap_size -= 1
        heap(alist, heap_size, 0)
if __name__ == '__main__':
    alist = [23, 4, 3, 5, 67, 32, 7, 24]
    heapsort(alist)
    print(alist)

8.基數排序

基數排序思想:基數排序的實現,是將原數組中的數值,分別按照個位,十位,百位......等的數值依次分組,比如,先按照個位數值分組,將原數組的元素按照個位數字進行依次分配,然後將分配好的元素,依次按照個位數字的大小依次存入到原數組中,然後再將該數組按照十位,百位....上的數字分組,最終實現排序。

基數排序(radix sort)屬於“分配式排序”(distribution sort),又稱“桶子法”(bucket sort)或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些“桶”中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,其時間複雜度爲O (nlog(r)m),其中r爲所採取的基數,而m爲堆數,在某些時候,基數排序法的效率高於其它的穩定性排序法。

def radix_sort(alist):
    """基數排序"""
    i = 0 # 記錄當前正在排拿一位,最低位爲1
    max_num = max(alist)  # 最大值
    j = len(str(max_num))  # 記錄最大值的位數
    while i < j:
        bucket_list =[[] for _ in range(10)] #初始化桶數組
        for x in alist:
            bucket_list[int(x / (10**i)) % 10].append(x) # 找到位置放入桶數組
        alist.clear()
        for x in bucket_list:   # 放回原序列
            for y in x:
                alist.append(y)
        i += 1

if __name__ == '__main__':
    alist = [23,4,3,5,67,32,7,24]
    radix_sort(alist)
    print(alist)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章