動畫:一篇文章快速學會插入排序

內容介紹

插入排序的思想

插入排序是將一個數據插入到已經排好序的有序數據中,從而獲得一個新的、個數加一的有序數據。java

咱們玩撲克牌時整理撲克牌就是典型的插入排序。以下動畫: 算法

插入排序正是如此,一邊摸牌,一邊理牌,將摸到的牌放到已經整理好的牌中。假如咱們手上已經有6,7,9,10,手上摸到的是8。處理方式就是先拿8和10比較,發現8小於10,再拿8和前面的9比較,發現8也是小於9,因而再和前面的7比,發現8大於7,最終就找到8應該放在7和9之間。編程

插入排序動畫演示

插入排序分析

通常沒有特殊要求排序算法都是升序排序,小的在前,大的在後。 數組由{6, 5, 4, 1, 3} 這5個無序元素組成。數組

插入排序原理:插入排序是將一個數據插入到已經排好序的有序數據中,從而獲得一個新的、個數加一的有序數據。微信

第一輪0索引對應的元素 6不用動。 性能

第二輪交換前圖示: 優化

第二輪是元素5須要插入到前面有序數列中,只須要和前面元素6比較並交換。動畫

第二輪交換後圖示: 3d

第三輪交換動畫: code

第三輪元素4須要先和元素6比較,4小於6,交換位置,元素4再和元素5比較,交換位置。詳細過程以下圖:

第四輪交換前圖示:

中間交換過程省略,第四輪交換後圖示:

第五輪交換前圖示:

第五輪交換後圖示:

插入排序代碼編寫

咱們分析了插入排序的原理,發現6個元素須要比較5輪,須要經過一個循環來控制,並且比較的輪數是元素的數量-1。每輪又須要拿當前元素和前面的元素比較也須要使用一個循環。所以須要使用嵌套循環來實現。

咱們須要關注插入排序何時須要交換位置,何時中止,以下圖所示: 由上圖可知,當要插入的元素小於前面的元素須要交換位置,當要插入的元素不小於要插入的元素則中止比較。

Java代碼以下:

public class InsertionSortTest2 {
    public static void main(String[] args) {
        int[] arr = new int[] {6, 5, 1, 3, 2};
        insertionSort(arr);
    }

    // 插入排序的基本操做就是將一個數據插入到已經排好序的有序數據中,從而獲得一個新的、個數加一的有序數據
    public static void insertionSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            for (int j = i; j > 0; j--) {
                if (arr[j] < arr[j-1]) {
                    swap(arr, j, j-1); // 要插入的數據小於前面的數據,和前面的數據換位置
                } else {
                    break; // 已經找到合適的位置插入,能夠提早終止這個循環了
                }
            }
            System.out.println("第" + (i + 1) + "輪元素插入後: " + Arrays.toString(arr));
        }
    }

    public static void swap(int[] arr, int start, int end) {
        int temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
    }
}

執行效果:

第2輪元素插入後: [5, 6, 1, 3, 2]
第3輪元素插入後: [1, 5, 6, 3, 2]
第4輪元素插入後: [1, 3, 5, 6, 2]
第5輪元素插入後: [1, 2, 3, 5, 6]

插入排序優化

如今插入排序的問題在於每次都是比較並交換兩個元素。

交換是須要消耗性能的,其實只須要找到合適的位置將要插入的元素放入進去,減小交換次數。動畫效果以下:

優化後代碼:

public class InsertionSortTest {
    public static void main(String[] args) {
        int[] arr = new int[] {6, 5, 1, 3, 2};
        insertionSort2(arr);
    }

    // 對插入元素進行優化,沒必要每次都是兩兩交換.一次移動一個元素,而後將元素插入到指定位置便可 
    public static void insertionSort2(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int e = arr[i]; // 獲得當前這個要插入的元素
            int j; // 記錄這個元素應該插入到哪一個位置
            for (j = i; j > 0 && arr[j-1] > e; j--) {
                arr[j] = arr[j-1]; // 若是j-1位置的元素大於要插入的元素元素e,將j-1位置的元素移動到j這個位置
            }
            arr[j] = e; // 將j這個位置保存要插入的數據e
        }
    }
}

插入排序複雜度

咱們來分析一下插入排序算法,從空間上來看,它只須要一個變量的輔助空間,所以關鍵是看它的時間複雜度。

  1. 當最好的狀況,也就是要排序的數據自己就是有序的,好比數據是 {1, 2, 3, 5, 6},只須要比較arr[1]與arr[0],比較arr[2]和arr[1],比較arr[3]和arr[2],比較arr[4]和arr[3],其實就是比較arr[j]與arr[j-1], 共比較了j-1次,時間複雜度爲0(n)。

  2. 當最壞的狀況,即待排序數據是逆序的狀況,好比{6, 5, 3, 2, 1},此時須要比較(n+2)(n-1)/2次。

  3. 若是排序記錄是隨機的,那麼根據機率相同的原則,平均比較和移動次數約爲n平方/4次。所以,咱們得出直接插入排序法的時間複雜度爲O(n^2)。

  4. 從這裏也看出,一樣的O(n^2)時間複雜度,直接插入排序法比冒泡和簡單選擇排序的性能要好一些,由於當數據比較有序的時候能夠提早終止排序。

總結

  1. 插入排序是將一個數據插入到已經排好序的有序數據中,從而獲得一個新的、個數加一的有序數據。

  2. 當arr[j]小於arr[j-1],也就是要插入的數據小於前面的數據,則交換位置。

  3. 當arr[j]不小於arr[j-1],也就是要插入的數據大於或等於於前面的數據,則不交換位置。

  4. 因爲插入排序一旦找到要插入的位置,能夠提早終止,從效率上來講比冒泡排序和選擇排序要高。尤爲是當數據近乎有序的時候,插入排序效率接近O(n),所以在一些其餘排序過程當中,當數據近乎有序或數據量小時,會將插入排序做爲一個子過程,進行排序優化。


原創文章和動畫製做真心不易,您的點贊就是最大的支持! 想了解更多文章請關注微信公衆號:表哥動畫學編程

相關文章
相關標籤/搜索