1. 程式人生 > >二分法插入排序

二分法插入排序

原理:

同直接插入排序一樣,二分法插入排序的原理也是將一個待排序的數,插入到前面已經排好序的陣列中,但是相比於直接插入排序來說,二分法插入排序是首先將新插入的數與前面已經排好序的陣列中的中間那個數進行比較,如果比中間的數大就再在中間的數之後的陣列中進行上訴比較,如果比中間的值小就再在中間的值之前的陣列中進行上訴比較,直到找到待插入數的正確位置.

其實上面的原理對應兩種情況(情況1,情況2),舉例如下:


情況1 (L>M-1)

假設有一個已經排好序的陣列:1 3 5 7,將其最左邊的數標為left(L),最右邊的數標為right(R),中間索引對應的數標為middle(M),如下:

1   3   5   7
L   M       R

如果在上訴陣列中再插入一個數,那麼有且僅有兩種情況①這個數大於M,②這個數不大於M(小於等於M),比如說插入的是4,則M<4,那麼我們讓L=M+1,則L,M,R在陣列中指向的索引如下:

1   3   5   7
        L   R
        M

此時再利用M與要插入的數字4進行比較,發現M>4了,則R = M-1,而R在這個時候也就小於L了(L>M-1),則我們就找到了要插入的數字4應該插入的位置,該位置就是L現在所指向的索引


情況2(R < M-1)

1   3   5   7
L   M       R

還是上面地陣列,如果一開始往這個數組裡插入的是8,此時M>6,則L = M+1,這個時候L,M,R在陣列中指向的索引如下:

1   3   5   7
        L   R
        M

此時再利用M與要插入的數字6進行比較,發現M>6,則L = M+1,這個時候L,M,R在陣列中指向的索引如下:

1   3   5   7
            L
            M
            R

此時再利用M與要插入的數字6進行比較,發現M>6,則L = M+1,這個時候L就大於R了(R < M+1),而此時我們也找到了要插入的數字8應該插入的位置,該位置也是L現在所指向的位置.

可以想象,無論排好序的陣列再怎樣變化,待插入的數字都將會面臨上面的兩種情況.而此時左指標L的位置就是要插入的數所在的位置,那麼該位置及到已排好序的陣列末尾位置(即待插入位置之前的那個位置)的數都要往後挪動1個位置,等待該數的插入.

本人寫的一段示例程式碼如下:

package com.nrsc.sort;

public class BinaryInsertSort {
    public static void main(String[] args) {
        int[] arr = { 49, 38, 65, 97, 23, 22, 76, 1, 5, 8, 2, 0, -1, 22 };

        binaryInsertSort(arr);

        System.out.println("排序後:");
        for (int i : arr) {
            System.out.println(i);
        }
    }

    private static void binaryInsertSort(int[] arr) {
        // 從陣列中的第二個數開始往前看
        for (int i = 1; i < arr.length; i++) {
            int left = 0;
            int right = i - 1;
            int middle = 0;
            int tmp = arr[i]; // 新遍歷的值等待插入到前面的有序陣列

            // 找到新遍歷的值應該插入的正確位置-----跳出下面的迴圈時,left的值就是要找的新位置
            while (left <= right) {
                middle = (left + right) / 2;
                if (arr[middle] < tmp) {
                    left = middle + 1;
                } else {
                    right = middle - 1;
                }
            }

            // 將left到i-1之間的數都往後移動一個位置----注意如果要插入的數比前面排好序的數都大,則不會進入到該迴圈內
            // 則此時將不會有數進行位置的移動
            for (int j = i - 1; j >= left; j--) {
                arr[j + 1] = arr[j];
            }

            //將tmp放到正確的位置
            //不加這個if也是對的,如果新插入的數比前面的有序陣列都大時,則left = i
            //這個時候arr[left] = tmp和不對該數尋找位置(不進入if語句),直接去遍歷下一個數是一個意思
            if (left != i) {
                arr[left] = tmp;
            }
        }

    }
}