插入排序(Insertion Sort)

Acx7發表於2021-04-04

介紹:

  直接插人排序的工作方式像許多人排序一手撲克牌。開始時,我們的左手為空並且桌子上的牌面向下。然後,我們每次從桌子上拿走一張牌並將它插入左手中正確的位置。為了找到一張牌的正確位置,我們從右到左將它與已在手中的每張牌進行比較。如圖2-1所示,拿在左手上的牌總是排序好的,原來這些牌是桌子上牌堆中頂部的牌。對於少量元素的排序,插入排序是一個有效的演算法。

思想:

  首先我們將陣列中的資料分為兩個區間,已排序區間和未排序區間。初始已排序區間只有一個元素,就是陣列的第一個元素,然後在未排序區間中依次取出元素並插入到已排序區間的合適位置,並保證已排序區間一直是有序。重複這個步驟直到未排序區間元素為空,排序完成。

效能分析:

  時間複雜度:O(N^2)

  空間複雜度:O(1)

  穩定性:穩定

程式碼實現:

// Java程式碼
class StraighInsertionSort {
    public static void straightInsertionSort(int[] array) {
        for (int i = 1; i < array.length; ++i) {// 遍歷無序序列
            int key = array[i];// 記錄準備插入的元素
            int j = i - 1;// 記錄當前比較位置指標
            
            while (j >= 0 && array[j] > key) {// 尋找插入位置
                array[j + 1] = array[j];// 元素後移 
                --j;// 指標減1,當前比較位置前移
            }
            array[j + 1] = key;// 插入合適位置
        }
    }
}
// C++程式碼
class StraightInsertionSort {
public:
    static void straightInsertionSort(int array[], int length) {
        for (int i = 1; i < length; ++i) {// 遍歷無序序列
            int key = array[i];// 記錄準備插入的元素
            int j = i - 1;// 記錄當前比較位置指標
            
            while (j >= 0 && array[j] > key) {// 尋找插入位置
                array[j + 1] = array[j];// 元素後移 
                --j;// 指標減1,當前比較位置前移
            }
            array[j + 1] = key;// 插入合適位置
        }
    }
};

演算法優化:

  上面的程式碼在有序序列中查詢時採用順序查詢,既然是有序序列,自然可以想到採用二分查詢減少查詢次數。時間複雜度還是 O(N^2),因為不管是二分查詢還是順序查詢,大部分時間都花在遍歷和元素的後移上,二分查詢只能在查詢位置上節約時間。

// Java程式碼
class BinaryInsertionSort {
    public static void binaryInsertionSort(int[] array) {
        for (int i = 1; i < array.length; ++i) {// 遍歷無序序列
            int left = 0;// 有序序列左指標
            int right = i - 1;// 有序序列右指標
            int key = array[i];// 記錄準備插入的元素
                    
            while (left <= right) {
                int mid = (left + right) / 2;// 有序序列中間位置
            
                if (array[mid] < key) {// 二分查詢
                    left = mid + 1;
                } else {// array[mid] >= key兩種情況合併,便於後續統一處理
                    right = mid - 1;
                }
            }
            // 找到元素插入位置後,整體後移
            for (int j = i - 1; j >= left; --j) {
                array[j + 1]  = array[j];
            }
            array[left] = key;// 填入對應位置
        }
    }
}
// C++程式碼
class BinaryInsertionSort {
public:
    static void binaryInsertionSort(int array[], int length) {
        for (int i = 1; i < length; ++i) {// 遍歷無序序列
            int left = 0;// 有序序列左指標
            int right = i - 1;// 有序序列右指標
            int key = array[i];// 記錄準備插入的元素
                    
            while (left <= right) {
                int mid = (left + right) / 2;// 有序序列中間位置
            
                if (array[mid] < key) {// 二分查詢
                    left = mid + 1;
                } else {// array[mid] >= key兩種情況合併,便於後續統一處理
                    right = mid - 1;
                }
            }
            // 找到元素插入位置後,整體後移
            for (int j = i - 1; j >= left; --j) {
                array[j + 1]  = array[j];
            }
            array[left] = key;// 填入對應位置
        }
    }
};

 

相關文章