排序法:選擇、冒泡、插入和快排

小丑与锁鸟發表於2024-04-11

排序方法指的是對一個無序的數列,按照一定方法讓其變得有序。排序法重點是思維過程,本文中的四種排序方法都較為基礎,但其中蘊含的演算法思維各不相同,適合作為演算法入門學習內容。

  • 選擇排序法
    我認為選擇排序法是較符合一般人思維模式的排序法,它是指對於每個數列,從其中找出最小的一個數字,將其放至首位,然後再不斷對剩餘的無序數列重複此操作。當剩餘無序數列的長度為0時,則完成排序。其python實現程式碼如下:
點選檢視程式碼
def select_sort(my_list):  
    n= len(my_list)        # n為數列長度
    for i in range(n-1):   # 共進行n-1次選擇(外迴圈),因為只要選出最小的n-1個數,最大的數就是剩下的,不需要進行額外操作天然已經位於數列末端
        min_i = i          # 初始化最小數字的索引為無序數列的第一個元素的索引,即假設第一個數字現在就是最小值。
        for j in range(i+1,n):  # 內迴圈處理無序數列中的每一個元素 
            if my_list[j]<my_list[min_i]:    #一旦無序數列中的數字比我們假設的初始值小,就將其索引記錄下來
                min_i = j
        if min_i != i:     # 一次內迴圈完成後,已經將無序數列中最小值的索引賦值給了min_i,如果其不同於無序數列的最左端(第一個)數字,則將兩者交換。交換完成後最小值已位於無序數列的最左段,此時可以將其視為有序數列的最右端,而不再是無序數列的一部分(透過外迴圈i的不斷增加來實現)
            my_list[i],my_list[min_i] = my_list[min_i],my_list[i]
選擇排序的時間複雜度O(n^2)
  • 氣泡排序法
    氣泡排序的過程是每次將最大的一個元素放至佇列末尾,這聽起來很像選擇排序的反過程。但是氣泡排序的實現是完全不同的。每一次排序,都是將無序數列的每一位,依次與其右邊的元素進行比較,並將其中較大的數字放在右邊。如此操作,大的數字會不斷被向右移,直至遇到比他更大的數字。這個更大的數字會接過其接力棒,再次向右進行比較,直到到達無序數列的最後一位。程式碼實現如下:
點選檢視程式碼
def bubble_sort(my_list):
    listlen = len(my_list)
    for i in range(listlen-1):  # i 代表輪次,範圍為0到n-2共n-1次(最大的n-1個數字排完無需再排第n個)
        for j in range(listlen-1-i):   # j 為每輪進行比較的第一個數字,因為最後的i個數字已經完成了排序,所以每次都是比較(n-1)-i個數字即可。對於第一輪
            if my_list[j]>my_list[j+1]: # 如果比右邊數字大,則進行交換
                my_list[j],my_list[j+1]=my_list[j+1],my_list[j]
氣泡排序的時間複雜度O(n^2)
  • 插入排序
    插入排序是指將每個序列分為左右兩個部分,左邊是已經從小到大排序完成的數列,右邊是無序數列,依次將無序數列的第一位插入至有序數列中。對於一個未經過排序的數列,可以將第一個數字視作有序的(很顯然單獨一個數字必然是有序的),而將第二個數字開始的剩餘數字視為需要排序的無序數列。程式碼實現如下:
點選檢視程式碼
def insert_sort(my_list):
    n = my_list
    for i in range(1,n):             # i 表示現在要處理第i個數字(第0)位不需要處理,在處理完這n-1個數字後它會天然出現在應該出現的位置
        for j in range(i+1,0,-1):    # j 指示要進行比較的數字,每次與左邊的數字進行比較,如果小於左邊數字說明應該左移
            if my_list[j]<my_list[j-1]:
                my_list[j],my_list[j-1] = my_list[j-1],my_list[j]
            else:
                break
插入排序的時間複雜度為O(n^2)
  • 快速排序
    快速排序的邏輯很簡單,但是程式碼實現會稍微複雜一點。原理是:隨便選取一個數字,將數列中比其小的數字都放到它左側,比它大的數字都放在它右側,以此來確定其在數列中的位置;之後,再對於每個沒有確定下來的數列區間重複此操作,直至每個數字都位於正確的位置。快排使用了遞迴的方式去排序,程式碼實現如下:
點選檢視程式碼
def quick_sort(my_list,start,end):
    """
    快速排序
    :param my_list: 要排序的列表
    :param start: 表示從哪個位置開始排序
    :param end: 表示到哪個位置結束排序
    :return: 如果start>=end,則表示排序完成,否則需要繼續排序
    """
    if start >=end:  # 當一個區間的長度為1或0時,說明已經排好序,則直接返回
        return
    left = start  #左指標為區間的第一個元素
    right = end   #右指標
    mid = my_list[start]   # 選取第一個元素作為中間值(基準值)。此時左指標位置空出來了
    while left < right:    # 左右指標向中間移動,直到左右指標相遇
        while my_list[right]>=my_list and left <right:  # 右指標向左移動,直到遇到小於等於基準值的元素
            right-=1
        my_list[left] = my_list[right]   # 將小於等於基準值的元素放到左指標位置
        while my_list[left]<my_list and left <right:   # 左指標向右移動,直到遇到大於等於基準值的元素
            left+=1
        my_list[right] = my_list[left]   # 將大於等於基準值的元素放到右指標位置
    my_list[left] = mid   # 經過上述的兩次交換之後,可能存在兩種情況:1.左右指標相遇;2.左指標的值已經賦給了右指標的位置。無論哪種情況,都需要將基準值放到左指標的位置。
    # 遞迴左半區間。如果 start=left-1,說明這次排序完之後左半區只有一個元素,不需要再排序。如果start>left-1,說明左半區為空,不需要再排序。
    quick_sort(my_list,start,left-1)
    quick_sort(my_list,right+1,end)      # 遞迴右半區間

相關文章