數據結構與算法系列——排序(3)_折半插入排序

1. 工做原理(定義)

  二分插入排序(Binary Insertion Sort,折半插入排序 OR 拆半插入排序),採用折半查找方法。 html

  二分查找插入排序的原理:是直接插入排序的一個變種;區別是:在有序區中查找新元素插入位置時,爲了減小元素比較次數提升效率,採用二分查找算法進行插入位置的肯定。java

2. 算法步驟

    設數組爲a[0…n]。 
  1. 將原序列分紅有序區和無序區。a[0…i-1]爲有序區,a[i…n] 爲無序區。(i從1開始) 
  2. 從無序區中取出第一個元素,即a[i],使用二分查找算法在有序區中查找要插入的位置索引j。 
  3. 將a[j]到a[i-1]的元素後移,並將a[i]賦值給a[j]。 
  4. 重複步驟2~3,直到無序區元素爲0。git

  這裏寫圖片描述

3. 圖片演示

  

 

4. 性能分析

1. 時間複雜度

  不難看出,折半插入排序僅僅是減小了比較元素的次數,約爲O(nlogn),並且該比較次數與待排序表的初始狀態無關,僅取決於表中的元素個數n;而元素的移動次數沒有改變,它依賴於待排序表的初始狀態。所以,折半插入排序的時間複雜度仍然爲O(n²),但它的效果仍是比直接插入排序要好。 github

  最好時間複雜度O(n)算法

  平均時間複雜度O(n²)數組

  最壞時間複雜度O(n²)數據結構

2. 空間複雜度

  插入排序過程當中,須要一個臨時變量temp存儲待排序元素,所以空間複雜度爲O(1)性能

3. 算法穩定性 

  插入排序是一種穩定的排序算法。學習

4. 優缺點

  • 優勢 : 穩定,相對於直接插入排序元素減小了比較次數;
  • 缺點 : 相對於直接插入排序元素的移動次數不變;

5. 優化

2-路插入排序算法是在折半插入排序的基礎上對其進行改進,減小其在排序過程當中移動記錄的次數從而提升效率。優化

具體實現思路爲:另外設置一個同存儲記錄的數組大小相同的數組 d,將無序表中第一個記錄添加進 d[0] 的位置上,而後從無序表中第二個記錄開始,同 d[0] 做比較:若是該值比 d[0] 大,則添加到其右側;反之添加到其左側。

在這裏的數組 d 能夠理解成一個環狀數組。

使用 2-路插入排序算法對無序表{3,1,7,5,2,4,9,6}排序的過程以下:

  • 將記錄 3 添加到數組 d 中:


     
  • 而後將 1 插入到數組 d 中,以下圖所示:


     
  • 將記錄 7 插入到數組 d 中,以下圖所示:


     
  • 將記錄 5 插入到數組 d 中,因爲其比 7小,可是比 3 大,因此須要移動 7 的位置,而後將 5 插入,以下圖所示:


     
  • 將記錄 2 插入到數組 d 中,因爲比 1大,比 3 小,因此須要移動 三、七、5 的位置,而後將 2 插入,以下圖所示:


     
  • 將記錄 4 插入到數組 d 中,須要移動 5 和 7 的位置,以下圖所示:


     
  • 將記錄 9 插入到數組 d 中,以下圖所示:


     
  • 將記錄 6 插入到數組 d 中,以下圖所示:


     

  最終存儲在原數組時,從 d[7] 開始依次存儲。

  2-路插入排序相比於折半插入排序,只是減小了移動記錄的次數,沒有根本上避免,因此其時間複雜度仍爲O(n2)

6. 具體代碼

import java.util.Arrays;

public class BinaryInsertionSort{
    public static void main(String[] args) {
        int[] arr = {8,7,6,5,4,3,2,1};
        System.out.println(Arrays.toString(binaryInsertionSort2(arr)));
    }

    // 二分插入排序
    public static int[] binaryInsertionSort(int[] sourceArray) {
        // 對 arr 進行拷貝,不改變參數內容
        int len =  sourceArray.length;
        int[] arr = Arrays.copyOf(sourceArray, len);
        // 從下標爲1的元素開始選擇合適的位置插入,由於下標爲0的只有一個元素,默認是有序的
        for (int i = 1; i < len; i++) {
            int left = 0;
            int right = i-1;
            int tmp = arr[i]; // 記錄要插入的數據
            while(left <= right) {
                int mid = (left + right) / 2; //二分區域
                if(arr[mid] > tmp) {
                    right = mid - 1;       //向左縮小區域
                }else {
                    left = mid + 1;        //向右縮小區域,當等於的時候日後加一位,保證了穩定性
                }
            }
            //arr[left,i-1]的元素總體後移
            for(int j=i; j>=left+1; j--) {
                arr[j] = arr[j-1];
            }
            arr[left] = tmp;
        }
        return arr;
    }
    
    //改進的二分插入--2路插入排序
    public static int[] binaryInsertionSort2(int[] sourceArray){
        int first = 0;//分別記錄temp數組中最大值和最小值的位置
        int last = 0;
        int k = 0;
        int len = sourceArray.length;
        int[] arr = Arrays.copyOf(sourceArray, len);
        int[] temp = new int[len];
        temp[0] = arr[0];
        for (int i = 1; i < len; i++){
            // 待插入元素比最小的元素小
            if (arr[i] < temp[first]){
                first = (first - 1 + len) % len;
                temp[first] = arr[i];
            }
            // 待插入元素比最大元素大
            else if (arr[i] > temp[last]){
                last = (last + 1 + len) % len;
                temp[last] = arr[i];
            }
            // 插入元素比最小大,比最大小
            else {
                k = (last + 1 + len) % len;
                //當插入值比當前值小時,須要移動當前值的位置
                while (temp[((k - 1) + len) % len] > arr[i]) {
                    temp[(k + len) % len] =temp[(k - 1 + len) % len];
                    k = (k - 1 + len) % len;
                }
                //插入該值
                temp[(k + len) % len] = arr[i];
                //由於最大值的位置改變,因此須要實時更新final的位置
                last = (last + 1 + len) % len;
            }
        }
        // 將排序記錄複製到原來的順序表裏
        for (k = 0; k < len; k ++) {
            arr[k] = temp[(first + k) % len];
        }
        return arr;
    }
}

7. 參考網址

  1. 數據結構基礎學習筆記目錄
  2. 排序算法系列之直接插入排序
  3. https://visualgo.net/en/sorting
  4. https://www.runoob.com/w3cnote/insertion-sort.html
  5. https://github.com/hustcc/JS-Sorting-Algorithm
  6. https://baike.baidu.com/item/%E6%8A%98%E5%8D%8A%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F/8208853?fr=aladdin
  7. 2路插入排序算法詳解
相關文章
相關標籤/搜索