1. 程式人生 > >常見排序演算法時間複雜度、空間複雜度、穩定性總結

常見排序演算法時間複雜度、空間複雜度、穩定性總結

排序演算法分類

這裡寫圖片描述

排序演算法比較表格

排序演算法 平均時間複雜度 最壞時間複雜度 空間複雜度 是否穩定
氣泡排序 O(n2) O(n2) O(1)
選擇排序 O(n2) O(n2) O(1) 不是
直接插入排序 O(n2) O(n2) O(1)
歸併排序 O(nlogn) O(nlogn) O(n)
快速排序 O(nlogn) O(n2) O(logn) 不是
堆排序 O(nlogn) O(nlogn) O(1) 不是
希爾排序 O(nlogn) O(ns) O(1) 不是
計數排序 O(n+k) O(n+k) O(n+k)
基數排序 O(N∗M)O(N∗M) O(N∗M) O(M)

注:

1 歸併排序可以通過手搖演算法將空間複雜度降到O(1),但是時間複雜度會提高。

2 基數排序時間複雜度為O(N*M),其中N為資料個數,M為資料位數。

輔助記憶

  • 時間複雜度記憶- 
    • 冒泡、選擇、直接 排序需要兩個for迴圈,每次只關注一個元素,平均時間複雜度為O(n2)(一遍找元素O(n)O(n),一遍找位置O(n)O(n))
    • 快速、歸併、希爾、堆基於二分思想,log以2為底,平均時間複雜度為O(nlogn)(一遍找元素O(n),一遍找位置O(logn))
  • 穩定性記憶-“快希選堆”(快犧牲穩定性) 
    • 排序演算法的穩定性:排序前後相同元素的相對位置不變,則稱排序演算法是穩定的;否則排序演算法是不穩定的。

原理理解

1 氣泡排序

1.1 過程

氣泡排序從小到大排序:一開始交換的區間為0~N-1,將第1個數和第2個數進行比較,前面大於後面,交換兩個數,否則不交換。再比較第2個數和第三個數,前面大於後面,交換兩個數否則不交換。依次進行,最大的數會放在陣列最後的位置。然後將範圍變為0~N-2,陣列第二大的數會放在陣列倒數第二的位置。依次進行整個交換過程,最後範圍只剩一個數時陣列即為有序。

1.2 動圖

1.3核心程式碼

2 選擇排序

2.1 過程

選擇排序從小到大排序:一開始從0~n-1區間上選擇一個最小值,將其放在位置0上,然後在1~n-1範圍上選取最小值放在位置1上。重複過程直到剩下最後一個元素,陣列即為有序。

2.2 動圖


2.3核心程式碼

3 插入排序

3.1 過程

插入排序從小到大排序:首先位置1上的數和位置0上的數進行比較,如果位置1上的數大於位置0上的數,將位置0上的數向後移一位,將1插入到0位置,否則不處理。位置k上的數和之前的數依次進行比較,如果位置K上的數更大,將之前的數向後移位,最後將位置k上的數插入不滿足條件點,反之不處理。

3.2 動圖

 

3.3核心程式碼

4 歸併排序

4.1 過程

歸併排序從小到大排序:首先讓陣列中的每一個數單獨成為長度為1的區間,然後兩兩一組有序合併,得到長度為2的有序區間,依次進行,直到合成整個區間。

4.2 動圖

 

4.3核心程式碼

·遞迴實現

·迭代實現

5 快速排序

5.1 過程

快速排序從小到大排序:在陣列中隨機選一個數(預設陣列首個元素),陣列中小於等於此數的放在左邊,大於此數的放在右邊,再對陣列兩邊遞迴呼叫快速排序,重複這個過程。

5.2 動圖

 

5.3核心程式碼

6 堆排序

6.1 過程

堆排序從小到大排序:首先將陣列元素建成大小為n的大頂堆,堆頂(陣列第一個元素)是所有元素中的最大值,將堆頂元素和陣列最後一個元素進行交換,再將除了最後一個數的n-1個元素建立成大頂堆,再將最大元素和陣列倒數第二個元素進行交換,重複直至堆大小減為1。

  • 注:完全二叉樹 
    假設二叉樹深度為n,除了第n層外,n-1層節點都有兩個孩子,第n層節點連續從左到右。如下圖 
    這裡寫圖片描述

  • 注:大頂堆 
    大頂堆是具有以下性質的完全二叉樹:每個節點的值都大於或等於其左右孩子節點的值。 
    即,根節點是堆中最大的值,按照層序遍歷給節點從1開始編號,則節點之間滿足如下關係: 
    這裡寫圖片描述 (1<=i<=n/2)

6.2 動圖

 
 

6.3 核心程式碼(函式)

這裡寫圖片描述
注意!!!陣列從1開始,1~n。

7 希爾排序

7.1 過程

希爾排序是插入排序改良的演算法,希爾排序步長從大到小調整,第一次迴圈後面元素逐個和前面元素按間隔步長進行比較並交換,直至步長為1,步長選擇是關鍵。

7.2 動圖

這裡寫圖片描述 

7.3 核心程式(函式)

8 桶排序(基數排序和基數排序的思想)

8.1 過程

桶排序是計數排序的變種,把計數排序中相鄰的m個”小桶”放到一個”大桶”中,在分完桶後,對每個桶進行排序(一般用快排),然後合併成最後的結果。

8.2 圖解

8.3 核心程式

9 計數排序

9.1 過程

演算法的步驟如下: 
- 找出待排序的陣列中最大和最小的元素 
- 統計陣列中每個值為i的元素出現的次數,存入陣列C的第i項 
- 對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加) 
- 反向填充目標陣列:將每個元素i放在新陣列的第C(i)項,每放一個元素就將C(i)減去1

9.2 圖解

這裡寫圖片描述

9.3核心程式碼

10 基數排序

10.1 過程

基數排序是基於資料位數的一種排序演算法。 
它有兩種演算法 
①LSD–Least Significant Digit first 從低位(個位)向高位排。 
②MSD– Most Significant Digit first 從高位向低位(個位)排。 
時間複雜度O(N*最大位數)。 
空間複雜度O(N)。

10.2 圖解

這裡寫圖片描述 
對a[n]按照個位0~9進行桶排序: 
這裡寫圖片描述 
對b[n]進行累加得到c[n],用於b[n]中重複元素計數 
!!!b[n]中的元素為temp中的位置!!!跳躍的用++補上: 
這裡寫圖片描述 
temp陣列為排序後的陣列,寫回a[n]。temp為按順序倒出桶中的資料(聯合b[n],c[n],a[n]得到),重複元素按順序輸出: 
這裡寫圖片描述

10.3核心程式碼