數組排序-插入排序(Insertion Sort)



概念:

    有一個已經有序的數據序列,要求在這個已經排好的數據序列中插入一個數,但要求插入后此數據序列仍然有序,這個時候就要用到一種新的排序方法——插入排序法;插入排序的基本操作就是將一個數據插入到已經排好序的有序數據中,從而得到一個新的、個數加一的有序數據,算法適用於少量數據的排序,時間復雜度為O(n^2)。是穩定的排序方法。插入算法把要排序的數組分為兩部分:第一部分包含了這個數組的所有元素,但將最后一個元素除外(讓數組多一個空間才有插入的位置),而第二部分就只包含這個元素(即待插入的元素)。在第一部分排序完成以后,再將這個最后元素插入到已排好序的第一部分中。插入排序的基本思想就是:每步將一個待排序的記錄,按其關鍵碼值的大小插入前面已經排序的文件中適當位置上,直到全部插入完為止。


過程:

    直接插入排序是一種簡單的插入排序法,其基本思想是:把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中,直到所有的記錄插入完為止,得到一個新的有序序列。

    例如,已知待排序的一組記錄是:60,71,49,11,24,3,66

    假設在排序的過程中,前3個記錄已經按照關鍵碼值遞增的次序重新排列,構成一個有序序列:49,60,71。將待排序記錄中的第4個記錄(即11)插入上述有序序列,以得到一個新的含有4個記錄的有序序列。首先,應找到11的插入位置,再進行插入。可以將11放入數組的第一個單元r[0]中,這個單元稱為監視哨,然后從71起從右到左查找,11小於71,將71右移一個位置,11小於60,又將60右移一個位置,11小於49,又再將49右移一個位置,這時再將11與r[0]的值比較,11>=r[0],它的插入位置就是r[1]。假設11大於第一個值r[1]。它的插入位置應該在r[1]和r[2]之間,由於60已經右移了,留出來的位置正好留給11。后面的記錄依照同樣的方法逐個插入到該有序序列中。若記錄數為n,需進行n-1趟排序,才能完成。

    直接插入排序的算法思路:
        (1)設置監聽哨r[0],將待插入記錄的值賦給r[0];
        (2)設置開始查找的位置;
        (3)在數組中進行搜索,搜索中將第j個記錄后移,直至r[0].key >= r[j].key為止;
        (4)將r[0]插入r[j+1]的位置上。


示例:

package com.lxj.cnblogs;

/**
 * @author 劉小將
 * 測試插入排序
 */
public class InsertSort {

    public static void main(String[] args){
        int[] a = {3,44,38,5,47,15,36,26};          //聲明一個數組並給定值
        printArray(a);                              //輸出原始數組數據到控制台
        insertSort(a);                              //對數組a進行插入排序
        printArray(a);                              //將排序過的數組輸出到控制台
    }

    /**
     * 插入排序算法
     * @param a
     */
    public static void insertSort(int[] a){
        int i = 0;
        int j = 0;
        for (i = 1;i < a.length;i++){
            int temp = a[i];
            if(a[i-1] > a[i]){
                for(j = i-1;j >= 0;j--){
                    if(temp < a[j]){
                        a[j+1] = a[j];
                    }else {
                        break;
                    }
                }
                a[j+1] = temp;
            }
        }
    }

    /**
     * 輸出方法
     * @param array
     */
    public static void printArray(int[] array){
        for(int i : array){
            System.out.print(i + " ");
        }
        System.out.println();
    }

}

運行結果:

3 44 38 5 47 15 36 26 
3 5 15 26 36 38 44 47

原理:


類比:

    插入排序非常類似於整撲克牌。在開始摸牌時,左右是空的,牌面朝下放在桌上。接着,一次從桌上摸起一張牌,並將它插入到左手一把牌中的正確位置上。為了找到這張牌的正確位置,要將它與手中已有的牌從右到左進行比較。無論什么時候,左手中的牌都是排好序的。也許你沒有意識到,但其實你的思考過程是這樣的:現在抓到一張7,把它和手里的牌從右到左依次比較,7比10小,應該再往左插,7比5大,就插入到這里。為什么比較了10和5就確定了7的位置?為什么不用再比較左邊的4和2呢?因為這里有一個重要的前提:手里的牌已經是排好序的。現在我插了7之后,手里的牌仍然是排好序的,下次再抓到的牌還可以用這個方法插入。編程對一個數組進行插入排序也是同樣的道理,但和插入撲克牌有一點不同,不可能在兩個相鄰的存儲單元之間再插入一個單元,因此要將插入點之后的數據依次往后移動一個單元。


效率分析:

    如果輸入數組已經是排好序的話,插入排序出現最佳情況,其運行時間是輸入規模的一個線性函數。如果輸入數組是逆序排列的,將出現最壞情況。平均情況與最壞情況一樣,其時間代價是O(n^2)。
    穩定
    空間復雜度O(1)
    時間復雜度O(n^2)
    最差情況:反序,需要移動n*(n-1)/2個元素
    最好情況:正序,不需要移動元素
    數組在已排序或者是“近似排序”時,插入排序效率的最好情況運行時間為O(n);插入排序最壞情況運行時間和平均情況運行時間都為O(n^2)。
    通常,插入排序呈現出來二次排序算法中的最佳性能
    對於具有較少元素(如 n <= 15)的列表來說,二次算法十分有效。
    在列表已被排序時,插入排序是線性算法O(n)
    在列表“近似排序”時,插入排序仍然是線性算法。
    在列表的許多元素已位於正確的位置上時,就會出現“近似排序”的條件。
    通過使用O(nlog2n)效率的算法(如 快速排序)對數組進行部分排序,然后再進行選擇排序,某些高級的排序算法就是這樣實現的。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM