插入排序(Insertion Sort)是一種簡單直觀的排序算法,它的核心思想類似於我們整理撲克牌時的操作:將未排序的元素逐個插入到已排序部分的正確位置,從而逐步構建整個有序數組。這種算法適合小規模數據的排序,實現起來也比較容易理解。

基本思路

想象你手中有一副打亂的撲克牌,你會一張一張地將牌插入到正確的位置:
1. 從第2張牌開始(默認第1張牌已排序),將當前牌記爲「待插入元素」。
2. 將待插入元素與已排序部分的牌從後往前比較:
- 如果已排序的牌比待插入元素大,就把這張已排序的牌後移一位。
- 重複此過程,直到找到一個比待插入元素小的牌,或者已經比較到最左邊。
3. 將待插入元素插入到這個位置,此時已排序部分長度增加1。
4. 重複步驟1-3,直到所有牌都插入完畢。

Java代碼實現

以下是使用Java實現插入排序的完整代碼,包含詳細註釋:

public class InsertionSort {

    // 插入排序方法
    public static void insertionSort(int[] arr) {
        // 數組爲空或只有一個元素時,本身已排序,無需操作
        if (arr == null || arr.length <= 1) {
            return;
        }

        // 從第2個元素開始(索引1),逐步將元素插入到已排序部分
        for (int i = 1; i < arr.length; i++) {
            // 保存當前待插入的元素
            int current = arr[i];
            // j表示已排序部分的最後一個元素的索引,初始爲i-1
            int j = i - 1;

            // 比較已排序部分的元素,若比current大則後移
            // 循環終止條件:j >= 0 且 arr[j] > current
            while (j >= 0 && arr[j] > current) {
                arr[j + 1] = arr[j]; // 將已排序元素後移一位
                j--; // 繼續向前比較前一個元素
            }

            // 找到插入位置,將current放入arr[j+1]
            arr[j + 1] = current;
        }
    }

    // 測試方法:驗證排序是否正確
    public static void main(String[] args) {
        int[] arr = {5, 2, 4, 6, 1, 3};
        System.out.println("排序前:" + java.util.Arrays.toString(arr));

        insertionSort(arr);

        System.out.println("排序後:" + java.util.Arrays.toString(arr));
    }
}

代碼執行過程解析

以數組 {5, 2, 4, 6, 1, 3} 爲例,逐步演示插入排序的過程:

初始數組:[5, 2, 4, 6, 1, 3]

第1輪(i=1,current=2):

  • 已排序部分:[5]
  • 比較:arr[0]=5 > 2,所以將5後移到 arr[1],j變爲-1
  • 插入位置:arr[0] = 2
  • 結果:[2, 5, 4, 6, 1, 3]

第2輪(i=2,current=4):

  • 已排序部分:[2, 5]
  • 比較:arr[1]=5 > 4,將5後移到 arr[2],j=0
  • 比較:arr[0]=2 <= 4,停止循環
  • 插入位置:arr[1] = 4
  • 結果:[2, 4, 5, 6, 1, 3]

第3輪(i=3,current=6):

  • 已排序部分:[2, 4, 5]
  • 比較:arr[2]=5 <= 6,無需移動
  • 插入位置:arr[3] = 6
  • 結果:[2, 4, 5, 6, 1, 3](數組未變化)

第4輪(i=4,current=1):

  • 已排序部分:[2, 4, 5, 6]
  • 比較:arr[3]=6 > 1 → 後移6到 arr[4],j=2
  • 比較:arr[2]=5 > 1 → 後移5到 arr[3],j=1
  • 比較:arr[1]=4 > 1 → 後移4到 arr[2],j=0
  • 比較:arr[0]=2 > 1 → 後移2到 arr[1],j=-1
  • 插入位置:arr[0] = 1
  • 結果:[1, 2, 4, 5, 6, 3]

第5輪(i=5,current=3):

  • 已排序部分:[1, 2, 4, 5, 6]
  • 比較:arr[4]=6 > 3 → 後移6到 arr[5],j=3
  • 比較:arr[3]=5 > 3 → 後移5到 arr[4],j=2
  • 比較:arr[2]=4 > 3 → 後移4到 arr[3],j=1
  • 比較:arr[1]=2 <= 3,停止循環
  • 插入位置:arr[2] = 3
  • 最終結果:[1, 2, 3, 4, 5, 6]

算法特性總結

  1. 時間複雜度
    - 最好情況(數組已排序):O(n)(僅需n-1次比較)
    - 最壞情況(數組逆序):O(n²)(n-1次內層循環,每次比較n次)
    - 平均情況:O(n²)

  2. 空間複雜度:O(1)(原地排序,僅需一個臨時變量保存待插入元素)

  3. 穩定性:穩定排序(相等元素的相對順序不會改變)

  4. 適用場景:適合小規模數據或幾乎有序的數據,因爲小規模數據的O(n²)影響較小。

總結

插入排序的核心是“逐步插入”,通過將元素與已排序部分比較並移動,最終構建有序數組。Java實現時需要注意保存待插入元素(避免覆蓋),以及正確處理邊界條件(j的終止條件)。這種算法雖然時間複雜度較高,但實現簡單,穩定性和原地性使其在小規模數據排序中表現良好。

小夜