# 插入排序法(Insert Sort) 把 n 個待排序的元素看成為一個有序表和一個無序表,開始時有序表只包含一個元素,無序表中包含 n-1 個元素,排序過程中每次從無序表中取出第一個元素,把它依次與有序表元素的元素進行比較,將它插入到有序表中的適當位置,使之成為新的有序表。 ## 舉例說明 假設今天有一陣列為 17, 3, 25, 14, 20, 9 ,我們需要利用插入排序法將之排序為由小到大: 1. 我們先將 17 設為有序表的第一個元素 (17), 3, 25, 14, 20, 9 2. 接著在無序表中取出第一個值,與有序表中的元素做比較,放置到合適的位置。 比如:3 < 17,所以將 3 置於 17 前方 4. 接下來是將 25 插入到有序表中,25 > 17 所以置於 17 後方 以此類推... ![](https://i.imgur.com/syAEpc1.png) ## 程式碼實現 1. 需要進行 陣列大小-1 輪比較 2. 第 n 輪需比較 n 個數 直接上程式碼更容易理解: ```java= package Sort; import java.util.Arrays; public class InsertSort { public static void main(String[] args) { int []arr = {17, 3, 25, 14, 20, 9}; insertSort(arr); } public static void insertSort(int [] arr) { for(int i = 1; i < arr.length; i++) { // 定義待插入的數 int insertVal = arr[i]; int insertIndex = i-1; // 即 arr[i] 前面這個數的索引 // 給insertVal找到插入的位置 // 1.保證在insertVal找插入位置, 不越界 // 2.insertVal < arr[insertIndex]待插入的數還沒找到插入位置 // 3.就需要將arr[insertIndex] 後移 while(insertIndex >= 0 && insertVal < arr[insertIndex]) { arr[insertIndex + 1] = arr[insertIndex]; insertIndex--; } // 當退出while循環時,說明插入的位置找到,insertIndex + 1 arr[insertIndex + 1] = insertVal; System.out.println("第"+(i+1)+"輪插入排序後 "+Arrays.toString(arr)); } } } ``` output ```java= 第2輪插入排序後 [3, 17, 25, 14, 20, 9] 第3輪插入排序後 [3, 17, 25, 14, 20, 9] 第4輪插入排序後 [3, 14, 17, 25, 20, 9] 第5輪插入排序後 [3, 14, 17, 20, 25, 9] 第6輪插入排序後 [3, 9, 14, 17, 20, 25] ``` ## 速度測試 一樣用八萬筆數據來做插入排序 ```java= public static void main(String[] args) { // int []arr = {17, 3, 25, 14, 20, 9}; int arr[] = new int[80000]; for(int i = 0; i < 80000; i++) { arr[i] = (int)(Math.random() * 80000); } Instant startTime = Instant.now(); insertSort(arr); Instant endTime = Instant.now(); System.out.println("共耗時:" + Duration.between(startTime, endTime).toMillis() + " 毫秒"); } ``` output ```java= 共耗時:1400 毫秒 共耗時:1395 毫秒 共耗時:1404 毫秒 共耗時:1402 毫秒 ``` 測試了三遍之後大概都是 1.4 秒,相較於泡沫排序法較快,但是較選擇排序法慢了一點。 ## 時間複雜度 假設今天要對一陣列使用插入排序法由小到大排序。 ### 最佳:O(1) 當資料順序恰好為由小到大時,每輪只需比較 1 次。 ### 平均:O(n^2^) 第 n 筆資料,平均需要比較 `n/2` 次。 ### 最差:O(n^2^) 當資料順序恰好為由大到小時,第 k 回合需比 k 次。 ## 存在的問題 此時有一個陣列 arr = {2,3,4,5,6,1},這時需要插入的數 1 為陣列中最小值,它所需要進行的過程為: {2,3,4,5,6,6} {2,3,4,5,5,6} {2,3,4,4,5,6} {2,3,3,4,5,6} {2,2,3,4,5,6} {1,2,3,4,5,6} 也就是說,當需要插入的數是較小的數時,後移的次數明顯增多,對效率有影響。 針對這個問題,有了更高效的插入排序改進版本—**希爾排序法(Shell Sort)**