【Python】(十五)Python中的排序(1)

排序是編程中最為常見的操作之一,也是極為基礎(chǔ)的算法。本節(jié)將快速回顧幾種經(jīng)典的排序方式,并用python實現(xiàn)它們。
為了簡單起見,我們只進行數(shù)字的排序,且統(tǒng)一為從小到大排序。(在實際的python使用中,可以直接用list.sort()函數(shù)完成排序。)

冒泡排序

冒泡排序需要多次遍歷列表。它比較相鄰的項并交換那些無序的項。每次遍歷列表將下一個最大的值放在其正確的位置。

# 冒泡排序
def bubble_sort(num_list):
    epochs = len(num_list)-1 #最多進行(列表長度-1)輪遍歷就可以完成排序
    for epoch in range(epochs):
        exchanged = False
        for i in range(len(num_list)-1-epoch): #每一輪都要進行(len(num_list)-1-epoch)次比較
            if num_list[i]>num_list[i+1]: #前一個元素大于后一個,需要交換
                temp = num_list[i]
                num_list[i] = num_list[i+1]
                num_list[i+1] = temp
                exchanged = True #本次遍歷發(fā)生了交換,記錄下來
        if False == exchanged: #本次遍歷沒有發(fā)生交換,表明序列已經(jīng)有序
            return num_list

def main():
    test_list = [54,26,93,17,77,31,44,55,20]
    print('冒泡排序:')
    print(bubble_sort(test_list))
    
if __name__ == "__main__":
    main()

運行結(jié)果為:

冒泡排序:
[17, 20, 26, 31, 44, 54, 55, 77, 93]

冒泡排序的時間成本很高,除非是每一次相鄰元素間的比較或交換有特殊的用途,否則不建議使用這種排序方式。

選擇排序

一個選擇排序在他遍歷時尋找最大的值,并在完成遍歷后,將其放置在正確的位置。與冒泡排序一樣,在第一次遍歷后,最大的項在正確的地方。 第二遍后,下一個最大的就位。遍歷 (n-1) 次排序 n 個項,因為最終項必須在第(n-1)次遍歷之后。選擇每次遍歷列表只做一次交換,因而通常情況下要快于冒泡排序。

# 選擇排序
def selection_sort(num_list):
    epochs = len(num_list)-1 #進行(列表長度-1)輪遍歷就可以完成排序
    for epoch in range(epochs):
        max_index = 0
        for i in range(len(num_list)-epoch): # 下標(biāo)從0到(len(num_list)-epoch-1)都是最大元素候選位置
            if num_list[i] > num_list[max_index]: #發(fā)現(xiàn)更大的元素,記錄其位置
                max_index = i
        #交換
        temp = num_list[max_index]
        num_list[max_index] = num_list[-epoch-1]
        num_list[-epoch-1] = temp
    return num_list
            
def main():
    test_list = [54,26,93,17,77,31,44,55,20]
    print('選擇排序:')
    print(selection_sort(test_list))
    
if __name__ == "__main__":
    main()

運行結(jié)果為:

選擇排序:
[17, 20, 26, 31, 44, 54, 55, 77, 93]

選擇排序雖然交換的次數(shù)更少,但選擇排序與冒泡排序有相同數(shù)量的比較,因此也是 O(n^2 )的時間復(fù)雜度。

插入排序

插入排序始終在列表中維護一個排序的子列表。然后將每個新項 “插入” 到這個排序好的子列表,并使得子列表繼續(xù)保持排序狀態(tài)。直到所有元素都被加入子列表則完成排序。
每一次“插入”操作都有O(n)的時間復(fù)雜度?!安迦搿辈僮骺梢跃唧w為子列表中比新元素大的都要后移一位,最終新元素直接放入合適的位置。

# 插入排序
def insertion_sort(num_list):
    for inserting_index in range(1, len(num_list)): #從索引1到列表最后一個元素逐個插入
        inserting_value = num_list[inserting_index]
        i = inserting_index-1 #從前一個元素開始,向前逐個比較
        while i>=0 :
            if num_list[i]>inserting_value: #比帶插入元素大的元素都需要后移一位
                num_list[i+1] = num_list[i]
            else: #找到了一個小于等于待插入元素的值,則插入上一個位置,并跳出循環(huán)
                num_list[i+1] = inserting_value
                break
            i -= 1 #向前
        num_list[i+1] = inserting_value # 在上一個位置插入
    return num_list
            
def main():
    test_list = [54,26,93,17,77,31,44,55,20]
    print('插入排序:')
    print(insertion_sort(test_list))
    
if __name__ == "__main__":
    main()

運行結(jié)果為:

插入排序:
[17, 20, 26, 31, 44, 54, 55, 77, 93]

插入排序的時間復(fù)雜度依然為O(n^2)。

希爾排序

希爾排序通過將原始列表分解為多個較小的子列表來改進插入排序。每個子列表使用插入排序進行排序。 這里不是將列表拆分為連續(xù)項的子列表,希爾排序使用增量方式,等距取元素組成子列表。這種拆分方式下,增量大小與子列表的數(shù)目相同。逐漸減小增量直至1,就可以得到排序好的列表。
我們將增量從長度的一半開始,每次都將增量減半,直至1。

# 希爾排序所需要的插入排序
# start_index為子序列的起始位置,increment為增量。
def shell_insertion_sort(num_list, start_index, increment):
    for inserting_index in range(start_index+increment, len(num_list), increment): #從索引(start_index+increment)到子列表的最后一個元素逐個插入
        inserting_value = num_list[inserting_index]
        i = inserting_index-increment #從前一個元素開始,向前逐個比較
        while i>=start_index :
            if num_list[i]>inserting_value: #比帶插入元素大的元素都需要后移增量位
                num_list[i+increment] = num_list[i]
            else: #找到了一個小于等于待插入元素的值,則插入上一個位置,并跳出循環(huán)
                num_list[i+increment] = inserting_value
                break
            i -= increment #向前
        num_list[i+increment] = inserting_value # 在上一個位置插入
    return num_list

# 希爾排序
def shell_sort(num_list):
    increment = len(num_list)//2 #增量的初值取列表長度的一半
    while increment > 0:
        for start_index in range(0,increment): #子列表的起始點
            shell_insertion_sort(num_list, start_index, increment) #為每個子列表排序
        increment = increment//2 #增量減半
    return num_list
            
def main():
    test_list = [54,26,93,17,77,31,44,55,20]
    print('希爾排序:')
    print(shell_sort(test_list))
    
if __name__ == "__main__":
    main()

運行結(jié)果為:

希爾排序:
[17, 20, 26, 31, 44, 54, 55, 77, 93]

希爾排序的時間復(fù)雜度很難計算,根據(jù)增量衰減的方式不同而不同,但整體傾向于落在 O(n) 和 O(n^2 ) 之間的某處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述 排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,303評論 0 52
  • 概述:排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    每天刷兩次牙閱讀 3,829評論 0 15
  • Ba la la la ~ 讀者朋友們,你們好啊,又到了冷鋒時間,話不多說,發(fā)車! 1.冒泡排序(Bub...
    王飽飽閱讀 1,898評論 0 7
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個記錄插入到已排序好...
    依依玖玥閱讀 1,355評論 0 2
  • 他的動畫總是能不刻意的擊中我心中的某一處。 《千與千尋》,是我第一次接觸宮老的動畫世界。千尋開始的膽小懦弱,沒見過...
    無言高高閱讀 938評論 1 3

友情鏈接更多精彩內(nèi)容