詳解直接插入排序演算法與相關的Java版代碼實現_java

來源:互聯網
上載者:User

直接插入排序

直接插入排序的思路很容易理解,它是這樣的:
1.把待排序的數組分成已排序和未排序兩部分,初始的時候把第一個元素認為是已排好序的。
2.從第二個元素開始,在已排好序的子數組中尋找到該元素合適的位置並插入該位置。
3.重複上述過程直到最後一個元素被插入有序子數組中。
4.排序完成。

樣本:
思路很簡單,但代碼並非像冒泡排序那麼好寫。首先,如何判斷合適的位置?大於等於左邊、小於等於右邊?不行,很多邊界條件需要考慮,而且判斷次數太多。其次,數組中插入元素,必然需要移動大量元素,如何控制它們的移動?
實際上,這並不是演算法本身的問題,而多少和程式設計語言有點關係了。有時候演算法本身已經很成熟了,到了具體的程式設計語言還是要稍作改動。這裡講的是Java演算法,那就拿Java說事兒。
為瞭解決上述問題,我們對第二步稍作細化,我們不從子數組的起始位置開始比較,而從子數組尾部開始逆序比較,只要比需要插入的數大,就向後移動。直到不大於該數的數,那麼,這個空出來的位置就安放需要插入的數字。因此,我們可以寫出以下代碼:
InsertArray.java

public class InsertArray {  // 數組  private long[] arr;  // 數組中有效資料的大小  private int elems;  // 預設建構函式  public InsertArray() {    arr = new long[50];  }  public InsertArray(int max) {    arr = new long[max];  }  // 插入資料  public void insert(long value) {    arr[elems] = value;    elems++;  }  // 顯示資料  public void display() {    for (int i = 0; i < elems; i++) {      System.out.print(arr[i] + " ");    }    System.out.println();  }  // 插入排序  public void insertSort() {    long select = 0L;    for(int i = 1; i < elems; i++) {      select = arr[i];      int j = 0;      for(j = i;j > 0 && arr[j - 1] >= select; j--) {        arr[j] = arr[j - 1];      }      arr[j] = select;    }  }}

測試類別:
TestInsertArray.java

public class TestInsertArray {  public static void main(String[] args) {    InsertArray iArr = new InsertArray();    iArr.insert(85);    iArr.insert(7856);    iArr.insert(12);    iArr.insert(8);    iArr.insert(5);    iArr.insert(56);    iArr.display();    iArr.insertSort();    iArr.display();  }}

列印結果:

演算法效能/複雜度
現在討論下直接插入演算法的時間複雜度。無論輸入如何,演算法總會進行n-1輪排序。但是,由於每個元素的插入點是不確定的,受輸入資料影響很大,其複雜度並不是一定的。我們可以分最佳、最壞、平均三種情況討論。
1.最佳情況:由演算法特點可知,當待排數組本身即為正序(數組有序且順序與需要的順序相同,於我們的討論前提,即為升序)時為最佳,理由是這種情況下,每個元素只需要比較一次且無需移動。演算法的時間複雜度為O(n);
2.最壞情況:很顯然,當待排數組為逆序時為最壞情況,這種情況下我們的每輪比較次數為i-1, 賦值次數為i。總的次數為級數2n-1的前n項和,即n^2.演算法的時間複雜度為O(n^2);
3.平均情況:由上述分析可以得到平均情況下演算法的運算次數大約為(n^2)/2(註:這裡計算以賦值和比較計,若按移動和比較,則大約為n^2/4),顯然,時間複雜度還是O(n^2)。
至於演算法的空間複雜度,所有移動均在資料內部進行,唯一的開銷是我們引入了一個臨時變數(有的資料結構書上稱為“哨兵”),因此,其空間複雜度(額外空間)為O(1)。

演算法穩定性
由於只需要找到不大於當前數的位置而並不需要交換,因此,直接插入排序是穩定的排序方法。

演算法變種
如果待排列的資料比較多,那麼每次從後往前找就造成了很大的開銷,為了提高尋找速度,可以採用二分尋找(Binary Search)進行效能最佳化。由於二分尋找的效率很高,保證了O(㏒n)複雜度,在資料比較多或輸入資料趨向最壞情況時可以大幅提高尋找效率。在有些書上將這種方法稱為折半插入排序。它的代碼實現比較複雜,以後有時間可以貼出來。
此外,還有2-路插入排序和表插入排序。2-路插入排序是在折半插入排序的基礎上進一步改進,其移動次數大為降低,大約為n^2/8。但是,它並不能避免移動次數,也不能降低複雜度層級。表插入排序則完全改變儲存結構,不移動記錄,但需要維護一個鏈表,以鏈表的指標修改代替移動記錄。因此,其複雜度仍然是O(n^2)。
有關2-路插入排序和表插入排序,可以參考嚴蔚敏、吳偉民編著的《資料結構》一書。

演算法適用情境
插入排序由於O(n^2)的複雜度,在數組較大的時候不適用。但是,在資料比較少的時候,是一個不錯的選擇,一般做為快速排序的擴充。例如,在STL的sort演算法和stdlib的qsort演算法中,都將插入排序作為快速排序的補充,用於少量元素的排序。又如,在JDK 7 java.util.Arrays所用的sort方法的實現中,當待排數組長度小於47時,會使用插入排序。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.