1. 程式人生 > >【算法】排序(四)歸並排序

【算法】排序(四)歸並排序

logs sta images pri 第一步 dom -o body 升序

上次給大家說了說簡單的冒泡排序,這次我們來說一說插入排序

插入排序的做法就像是我們日常生活中玩撲克牌一樣,每次抽一張牌,將撲克牌按一定順序插入手牌中,一步步完成排序


本文將介紹以下內容

排序思想
算法實現(JAVA)
測試階段
排序過程講解
算法分析

排序思想

插入排序同樣有內循環和外循環,外循環執行n - 1次,內循環負責比較相鄰兩個數的大小並交換(如果需要)。每次將未排序序列裏的第一個數與後一個數比較,如果後者小,就交換二者的位置,並和以排序的序列元素依次比較並交換(如果需要)。

就如同玩撲克牌,每次抽取的一張牌都要與所有手牌一對一比較,並確定最終插入的位置。

算法實現

1. 外循環

public static void insertionSort(int[] a) {
        int n = a.length;
        for (int i = 1; i < n; i++) {
        }
    }

循環次數為n - 1,否則數組下標越界,下文會說明原因。

2. 內循環

for (int j = i; j > 0 && a[j] < a[j - 1] ; j--) {
                int temp = a[j];
                a[j] = a[j - 1];
                a[j - 1] = temp;
            }

交換條件為後一項小於前一項,每次都是a[j]與a[j - 1] 比較,所以只能有n - 1 次循環,否則數組下標越界。

所以,插入排序的代碼塊就是如此了:

public static void insertionSort(int[] a) {
        int n = a.length;
        for (int i = 1; i < n; i++) {
            for (int j = i; j > 0 && a[j] < a[j - 1] ; j--) {           
                int temp = a[j];
                a[j] = a[j - 1];
                a[j - 1] = temp;
            }
        }
    }

測試階段

我們還是用十個隨機數字來作為輸入:

public static void main(String[] args){
        int[] a = new int[10];
        for (int i = 0; i < a.length; i++) {
            a[i] = (int)(Math.random()*100);
            System.out.print(a[i] + " ");
        }
        System.out.println();
        insertionSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i] + " ");
        }
    }

隨機選取幾組結果:
技術分享圖片
技術分享圖片
技術分享圖片

排序過程講解

我們以result_1的排序結果作為示例來解釋一下排序過程:

  • 第一步:74與11比較,交換順序,已排序序列為[11,74]

  • 第二步:74與99比較,不交換順序,已排序序列為[11,74,99]

  • 第三步:99與85比較,交換順序,85與74比較,不交換順序,已排序序列為[11,74,85,99]

  • 第四步:99與14比較,交換順序,85與14比較,交換順序,74與14比較,交換順序,已排序序列為[11,14,74,85,99]

  • 第五步:99與74比較,交換順序,85與74比較,交換順序,74與74比較,不交換順序,已排序序列為[11,14,74,74,85,99]

  • 第六步:99與24比較,交換順序,85與24比較,交換順序,74與24比較,交換順序,74與24比較,交換順序,14與24比較,不交換順序,已排序序列為[11,14,24,74,74,85,99]

  • 第七步:99與90比較,交換順序,85與90比較,不交換順序,已排序序列為[11,14,24,74,74,85,90,99]

  • 第八步:99與比54較,交換順序,85與54比較,交換順序,74與53比較,交換順序,74與54比較,交換順序,24與54比較,不交換順序,已排序序列為[11,14,24,54,74,74,85,99]

  • 第九步:99與82比較,交換順序,85與82比較,交換順序,
    74與82比較,不交換順序,已排序序列為[11,14,24,74,74,85,90,99]

n個元素的數組,經歷n - 1次排序,總而言之,如果兩元素比較,後者較小,就有可能多次比較,最後插入較前的位置。

算法分析

1. 特點

  • 插入排序對於較為有序(部分有序)的數組時極為高效,因為有序的兩個數不滿足內循環的循環條件,所以可以直接跳過,極大增加效率。

2. 時間復雜度

  • 最優情況:數組全部按升序排列,只需要進行n - 1次的比較就可完成,不需要交換

  • 最差情況:數組全部按降序排列,需要進行n(n - 1) / 2次比較
    (1 + 2 + 3 + ... + n - 1) = n(n - 1) / 2,需要進行n(n - 1) / 2次交換

  • 正常來說,插入排序的時間復雜度為O(n2)

3. 空間復雜度

插入排序需要一個臨時變量來交換元素,所以空間復雜度為O(1)

4. 穩定性

插入排序是穩定的,例如result_1中,排序前a[0] = a[5] = 74,且a[0]代表的74在a[5]代表的74之前。在排序過程中,兩個74相遇,並沒有交換位置,所以插入排序是穩定的

插入排序就講到這,下一篇文章將會是歸並排序。

【算法】排序(四)歸並排序