算法排序篇——選擇排序與插入排序

個人算法學習筆記:算法基礎之——SelectionSort,InsertionSortjava

  • 選擇排序原理
  • 選擇排序代碼的實現
  • 插入排序原理
  • 插入排序的代碼實現
  • 插入排序的優化

選擇排序原理

選擇排序動態演示
選擇排序示例:
git

原數組

選擇排序的思想是每次將未排序數組中的第一個元素與後面的元素依次比較,將最小的數字記錄下來,並同未排序數組中的第一個元素交換位置。

1

2

3

後續過程再也不演示。

選擇排序代碼的實現

public class SelectionSort{
    // 排序算法中不會產生任何實例
    private SelectionSort(){}
    public static void sort(Comparable[]arr){
        for(int i=0;i<arr.length;i++){
            int minIndex = i;
            for(int j=i+1;j<arr.length;j++){
                if(arr[minIndex].compareTo(arr[j])>0){
                    minIndex = j;
                }
            }
            Comparable temp = arr[minIndex];
            arr[minIndex] = arr[i];
            arr[i] = temp;
        }
    }
}
複製代碼

插入排序原理

插入排序動態演示
插入排序又叫撲克牌排序,我我的以爲撲克牌排序(PorkerSort)要比InsertionSort這個名字更讓人理解這個排序的過程。咱們在和別人打鬥地主的時候,將一張牌又一張牌抓在手裏的過程,這個過程實際上咱們就應用了插入排序這種思想。示例:
github

原數組

抓到了第一張牌:5,由於手裏只有一張牌因此至關於已經排好了序。

I1

抓到了第二張牌:8,將手裏全部的牌與抓到的牌進行比較放入合適的位置。

I2

後續過程再也不進行演示。

插入排序的代碼實現

將插入排序的過程轉換爲Java代碼:算法

public class InsertionSort{
    // 算法中不會產生任何實例
    private InsertionSort(){}
    public static void sort(Comparable[]arr){
        for(int i=1;i<arr.length;i++){
            for(int j=i;j>0;j--){
                if(arr[j].compareTo(arr[j-1])<0){
                    Comparable temp = arr[j];
                    arr[j] = arr[j-1];
                    arr[j-1] = temp;
                }else{
                    break;
                }
            }
        }
    }
}
複製代碼

在代碼中,第一個for循環for(int i=1;i<arr.length;i++),爲何i的取值是從1開始的呢?其實也不難想到,在咱們抓到第一張牌的時候,這張牌已是「排好序」的一張牌了,在咱們從抓第二張牌開始,纔會考慮到和手中的第一張牌做比較並排序的事情。另外本例的代碼還能夠在語法糖上進行簡化:數組

public class InsertionSort{
    private InsertionSort(){}
    public static void sort(Comparable[]arr){
        for(int i=1;i<arr.length;i++){
            for(int j=i;i>0 && arr[j].compareTo(arr[j-1]);j--){
                Comparable temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
            }
        }
    }
}
複製代碼

相比於選擇排序,插入排序彷佛要好那麼一些。選擇排序是一個"純正的"O(n^2)級別的算法,由於選擇排序不管如何都會堅持本身的使命,執行完代碼。而插入排序則不一樣,當新插入的元素比較到某個位置時發現它沒有這個位置的元素大,那麼程序就會break出這層循環。能夠形象地理解爲:選擇排序是「不撞南牆不回頭」,插入排序則更像是「見好就收」。試想一下:若是一個數組爲已經排好序的數組,可是咱們不知道它爲一個已經排好序的數組,須要使用某個算法對其進行排序,若是咱們使用了選擇排序,很顯然選擇排序依然會消耗O(n^2)的時間複雜度,而插入排序則不一樣,插入排序會從一個O(n^2)級別的算法進化爲一個O(n)級別的算法!如今對SelectionSort及InsertionSort進行測試。 測試代碼:測試
bash

test
上述的測試結果是我10次測試結果中第10次的截圖。測試內容爲隨機生成兩個arr.length==10000且數據範圍爲0~9999閉區間的數組,在jdk1.8的測試環境下的測試數據。我共作了10組測試,10組測試中,SelectionSort的時間都要優於InsertionSort,咱們的分析是插入排序要優於選擇排序,可是爲何會形成這樣的結果呢?

插入排序的優化

仔細分析插入排序與選擇排序,其實不難發現,出現上述測試結果的主要緣由就在swap(交換)上。插入排序算法,每插入一個元素,當發現被插入的元素小於前面的元素時,咱們馬上就讓兩者swap,若是繼續比較,被插入的元素仍然小於前面的元素,還要再次進行swap。插入排序的優化思想就是讓swap這個過程變爲一個簡單的賦值過程。如示例:
待插入的元素爲:「5」,先將元素「5」存儲起來。
學習

優化1

依次將帶插入的元素與前面的元素進行比較。與swap不一樣,這一次咱們使用賦值的思想。

優化2

將存儲的帶插入元素「5」,賦值到合適的位置。

優化3

代碼以下:

public class InsertionSort{
    // 算法中不會產生任何實例
    private InsertionSort(){}
    public static void sort(Comparable[]arr){
        for(int i=1;i<arr.length;i++){
            Comparable temp = arr[i];
            int j;
            for(j=i;j>0;j--){
                if(temp.compareTo(arr[j-1]){
                    arr[j] = arr[j-1];
                }
            }
            arr[j] = temp;
        }
    }
}
複製代碼

經測試,優化過的插入排序在時間上有了必定的壓縮。雖然作了幾回測試,優化的插入排序與選擇排序在時間上不分上下,可是須要知道的是插入排序的意義就在於對幾乎排好序的數據來講,時間複雜度近乎爲O(n),這個特性是選擇排序所沒有的。測試

相關文章
相關標籤/搜索