常見排序演算法詳解(冒泡、選擇、插入、快速、希爾、歸併)

来源:https://www.cnblogs.com/rungang/archive/2019/08/21/11391221.html
-Advertisement-
Play Games

一、排序演算法 1、冒泡排序(Bubble Sort) 定義:是一種簡單的排序演算法。它重覆地遍歷要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。遍曆數列的工作是重覆地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂 ...


一、排序演算法

1、冒泡排序(Bubble Sort)

定義:是一種簡單的排序演算法。它重覆地遍歷要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。遍曆數列的工作是重覆地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。

原理:

  • 比較相鄰的元素。如果第一個比第二個大(升序),就交換他們兩個。
  • 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
  • 針對所有的元素重覆以上的步驟,除了最後一個。
  • 持續每次對越來越少的元素重覆上面的步驟,直到沒有任何一對數字需要比較。
list1 = [12, 54, 23, 56, 67, 45, 1]

def bubbleSort():
    '''冒泡排序'''
    for i in range(len(list1) - 1, 0, -1):
        for j in range(i):
            if list1[j] > list1[j + 1]:
                list1[j], list1[j + 1] = list1[j + 1], list1[j]
        print(list1)

bubbleSort()

時間複雜度:

  • 最優時間複雜度:O(n) (表示遍歷一次發現沒有任何可以交換的元素,排序結束。)
  • 最壞時間複雜度:O(n2)
  • 穩定性:穩定

效果圖:

 

 

 2、選擇排序

定義:選擇排序(Selection sort)是一種簡單直觀的排序演算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。

list1 = [2, 6, 9, 5, 3, 1]

def selection_sort(list1):
    n = len(list1)
    # 需要進行n-1次選擇操作
    for i in range(n - 1):
        # 記錄最小位置
        min_pos = i
        # 從i+1位置到末尾選擇出最小數據
        for j in range(i + 1, n):
            if list1[j] < list1[min_pos]:
                min_pos = j
        # 如果選擇出的數據不在正確位置,進行交換
        if min_pos != i:
            list1[i], list1[min_pos] = list1[min_pos], list1[i]

        print('----》', list1)

selection_sort(list1)

時間複雜度:

  • 最優時間複雜度:O(n2)
  • 最壞時間複雜度:O(n2)
  • 穩定性:不穩定(考慮升序每次選擇最大的情況)

效果圖:

 

3、插入排序

定義:插入排序(英語:Insertion Sort)是一種簡單直觀的排序演算法。它的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。

list1 = [3, 2, 9, 5, 1, 0]


def insert_sort(list1):
    '''插入排序'''
    # 從第二個位置,即下標為1的元素開始向前插入
    for i in range(1, len(list1)):
        # 從第i個元素開始向前比較,如果小於前一個元素,交換位置
        for j in range(i, 0, -1):
            if list1[j] < list1[j - 1]:
                list1[j], list1[j - 1] = list1[j - 1], list1[j]
        print(list1)


insert_sort(list1)

時間複雜度:

  • 最優時間複雜度:O(n) (升序排列,序列已經處於升序狀態)
  • 最壞時間複雜度:O(n2)
  • 穩定性:穩定

 效果圖:

 

4、快速排序

定義:快速排序(英語:Quicksort),又稱劃分交換排序(partition-exchange sort),通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。

步驟為:

  1. 從數列中挑出一個元素,稱為"基準"(pivot),
  2. 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分區結束之後,該基準就處於數列的中間位置。這個稱為分區(partition)操作。
  3. 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。

遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,但是這個演算法總會結束,因為在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。

list1 = [89, 56, 34, 16, 98, 110, 78, 90]


def quik_sort(list1, start, end):
    '''快速排序'''
    # 遞歸退出的條件
    if start >= end:
        return
    
    # 設定起始元素要尋找位置的基準標準
    mid = list1[start]
    # low為序列左邊的由左向右移動的游標
    low = start
    # high為序列左邊的由右向左移動的游標
    high = end

    while low < high:
        # 若low與high未重合high指向的元素不比基準元素小,則high向左移動
        while low < high and list1[high] >= mid:
            high -= 1
        list1[low] = list1[high]
        # 若low與high未重合low指向的元素不比基準元素小,則low向左移動
        while low < high and list1[low] < mid:
            low += 1
        list1[high] = list1[low]
    
    # 退出迴圈後,low與high重合,此時所指位置為基準元素的正確位置
    # 將基準元素放到該位置
    list1[low] = mid
    
    # 左邊序列快速排序  遞歸
    quik_sort(list1, start, low - 1)
    # 右邊序列快速排序
    quik_sort(list1, low + 1, end)
    print(list1)


quik_sort(list1, 0, len(list1) - 1)

時間複雜讀:

  • 最優時間複雜度:O(nlogn)
  • 最壞時間複雜度:O(n2)
  • 穩定性:不穩定

演示:

 

 

 5、希爾排序

 定義:希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法。該方法因DL.Shell於1959年提出而得名。 希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,演算法便終止。

 基本思想:將數組列在一個表中並對列分別進行插入排序,重覆這過程,不過每次用更長的列(步長更長了,列數更少了)來進行。最後整個表就只有一列了。將數組轉換至表是為了更好地理解這演算法,演算法本身還是使用數組進行排序。

list1 = [23, 17, 77, 54, 12, 43, 65, 45]

def shell_sort(list1):
    '''插入排序'''
    n = len(list1)

    # 初始化步長
    gap = n // 2
    while gap > 0:
        # 按步長進行插入排序
        for i in range(gap, n):
            j = i
            while j >= gap and list1[j - gap] > list1[j]:
                list1[j - gap], list1[j] = list1[j], list1[j - gap]
                j -= gap

        gap = gap // 2
        print(list1)

shell_sort(list1)

 

 時間複雜度:

  • 最優時間複雜度:根據步長序列的不同而不同
  • 最壞時間複雜度:O(n2)
  • 穩定想:不穩定

演示:

 

6、歸併排序

定義:歸併排序是採用分治法的一個非常典型的應用。歸併排序的思想就是先遞歸分解數組,再合併數組。

將數組分解最小之後,然後合併兩個有序數組,基本思路是比較兩個數組的最前面的數,誰小就先取誰,取了後相應的指針就往後移一位。然後再比較,直至一個數組為空,最後把另一個數組的剩餘部分複製過來即可。

原理:

def merge_sort(list1):
    '''歸併排序'''
    if len(list1) <= 1:
        return list1
    # 二分分解
    num = len(list1) // 2
    left = merge_sort(list1[:num])
    right = merge_sort(list1[num:])
    print(left)
    print(right)
    # 進行合併
    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


list1 = [12, 34, 21, 56, 43, 67]
a = merge_sort(list1)
print(a)

 

 時間複雜度:

  • 最優時間複雜度:O(nlogn)
  • 最壞時間複雜度:O(nlogn)
  • 穩定性:穩定

 

 6種排序演算法比較:

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 使用Python採集SQL Server資料庫伺服器磁碟信息時,遇到了一個錯誤“CONFIG statement cannot be used inside a user transaction.DB-Lib error message 20018, severity 16”,那麼為什麼遇到這個錯誤... ...
  • 摘要: 大家都知道註解是實現了java.lang.annotation.Annotation介面,眼見為實,耳聽為虛,有時候眼見也不一定是真實的。 元註解: 元註解 一般用於指定某個註解生命周期以及作用目標等信息。正如源碼的註釋一樣,如果自定義的註解沒有添加元註解就和平常的註釋沒有多大的區別,有了元 ...
  • - 1.win10安裝JDK8 - 2.數據類型與變數 - 3.運算符 - 4.程式流程式控制制 - 5.數組 ...
  • 昨天花了一下午寫了一個小爬蟲,用來分析自己的粉絲數據。這個真好玩!今天幫了群里好多大V也爬了他們的數據。運行速度:每分鐘5千粉絲以上。暫時先寫成這樣,這兩天要準備補考,沒有時間繼續玩這個。 下次要改進的地方:1、多線程 2、scrapy 3、深度數據 4、分散式爬蟲 希望實現的功能: + 1、地區、 ...
  • 綁定事件: 解綁事件: 點擊事件:click 滑鼠:mousedown、mouseup、mousemove、mouseover、mouseout、mouseenter、mouseleave 對於input框:focus、blur、input input能夠實時檢測 textarea,input:te ...
  • unittest中的測試斷言分兩天總結,hhh其實內容不多,就是懶~ 斷言的作用是什麼? 答:設置測試斷言以後,能幫助我們判斷測試用例執行結果。 我們先看下unittest支持的斷言有哪些: 對上面的斷言語法有個大概的瞭解後,我們使用一下看看代碼: 一: 註意:相等,必須是內容和類型都完全相等哦,比 ...
  • String類常用的構造方法 1、String(byte[] bytes) 通過使用平臺的預設字元集解碼指定的 byte 數組,構造一個新的 String。 2、String(char[] value) 分配一個新的 String,使其表示字元數組參數中當前包含的字元序列。 3、String(cha ...
  • 之前操作了一個IDC網站,不到1個月的時間把網站的權重從0做到了1,本來想寫篇文章分享相關的操作經驗。後來因為網站整體規劃的原因,IDC網站需要關閉一段時間做備案的更新,排名肯定就會掉了,然後怕大家看到我後面網站的數據不是我分享說的樣子,說我騙人,就沒寫那次的分享經驗。 今天無意間通過站長工具查詢新 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...