介紹:
直接插人排序的工作方式像許多人排序一手撲克牌。開始時,我們的左手為空並且桌子上的牌面向下。然後,我們每次從桌子上拿走一張牌並將它插入左手中正確的位置。為了找到一張牌的正確位置,我們從右到左將它與已在手中的每張牌進行比較。如圖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;// 填入對應位置 } } };