『演算法』之 初級排序演算法總結

wcode發表於2019-02-10

本文內容是對『演算法』第四版 的摘要總結!
文章所用圖片部分來自 『演算法』第四版 英文原版 ,部分來自 『演算法』第四版 中文譯版

選擇排序

一種最簡單的排序演算法:首先,找到陣列中最小的那個元素,其次,將他和陣列中的第一個元素交換位置。再次,在剩下的元素中找到最小的元素,將它和陣列中的第二個元素換位置。如此往復,知道整個陣列有序,這種方法叫做選擇排序,因為它在不斷地選擇剩餘元素中之中的最小者。

每次交換都能排定一個元素,因此交換的總次數是 N。所以演算法的時間效率取決於比較的次數。

特點

  • 執行時間和輸入無關
  • 資料移動是最少的
    每次交換都會改變兩個陣列元素的值,因此選擇排序用了 N 次交換——–交換次數和陣列的大小是線性關係(大部分演算法都是線性對數或是平方級別)

具體程式碼

fun main(args: Array<String>) {
    val a = arrayOf(1, 32, 2, 23, 5, 234, 12, 978, 2, 2, 0, 4)

    for (i in 0 until a.size) {
        var min=i
        for (j in i until a.size){
            if(a[j]<a[min]){
                min=j
            }
        }
        val t=a[i]
        a[i]=a[min]
        a[min]=t
    }

    a.forEach { print("$it ") }
}
複製程式碼

選擇排序的軌跡(每次交換後的陣列內容)

『演算法』之 初級排序演算法總結

圖片來自 algs4.cs.princeton.edu

插入排序

通常人們整理撲克牌的方法是一張一張的來,將每一張牌插入到其他已經有序的牌中的適合位置。在計算機的實現中,為了給要插入的元素騰出空間,我們需要將其餘所有元素在插入之前都向右移動一位,這種演算法叫做插入排序。

特點

  • 和選擇排序一樣,當前索引左邊的所有元素都是有序的,但它們是我最終位置還不確定,為了給更小的元素騰出空間,它們可能會移動。當索引到達陣列的右端時,陣列就排序完成了
  • 執行時間和輸入有關,對一個很大且其中元素已經基本或接近有序的陣列進行排序會比對隨機順序的陣列或是逆序陣列進行排序要快得多。

具體程式碼

fun main(args: Array<String>) {
    val a = arrayOf(1, 32, 2, 23, 5, 234, 12, 978, 2, 2, 0, 4)

    for (i in 1 until a.size) {
        for (j in i downTo 1){
            if(a[j]<a[j-1]){
                val t=a[j]
                a[j]=a[j-1]
                a[j-1]=t
            }
        }
    }

    a.forEach { print("$it ") }
}
複製程式碼

對於 0 到 a.size-1 之間的每一個 i,將 a[i] 與 a[0] 到 a[i-1] 中比它小的所有元素一次有序地交換。在索引 i 由左向右變化的過程中,它左側的元素總是有序的,所以當 i 到達陣列的右端時排序就完成了。

插入排序的軌跡(每次交換後的陣列內容)

『演算法』之 初級排序演算法總結

圖片來自 algs4.cs.princeton.edu

插入排序非常適合部分有序的陣列,那“部分有序”是如何定義的?
部分有序陣列的幾種典型表現:

  • 陣列中每個元素距離它的最終位置都不遠。
  • 一個有序的大陣列接一個小陣列。
  • 陣列中只有幾個元素的位置不正確。

插入排序和選擇排序的軌跡比對圖

『演算法』之 初級排序演算法總結

圖片來自 algs4.cs.princeton.edu

希爾排序

希爾排序是一種基於插入排序的快速的排序演算法,它為了加快速度簡單地改進了插入排序,交換不相鄰的元素以對陣列的區域性進行排序,並最終用插入排序將區域性有序的陣列排序。

特點

使陣列中任意間隔為 h 的元素都是有序的。這樣的陣列被稱為 h 有序陣列。換句話說,一個 h 有序的陣列就是 h 個互相獨立的有序陣列編織在一起組成的一個陣列。

在進行排序時,如果 h 很大,我們就能將元素移動到很遠的地方,為實現更小的 h 有序創造方便。用這種方式,對於任意以 1 結尾的 h 序列,我們都能將陣列排序。

『演算法』之 初級排序演算法總結

一個 h 有序陣列(即一個由 h 個有序子陣列組成的陣列)
圖片來自 algs4.cs.princeton.edu

希爾排序的方式是:在 h 個子陣列中將每個元素交換到比它大的元素之前。只需要在插入排序的程式碼中將移動元素的距離由 1 改為 h 即可。

這樣,希爾排序的實現就轉化為了一個類似插入排序但使用不同增量的過程。

希爾排序高效的原因是它先將陣列排成部分有序,而部分有序剛好很適合插入排序

具體程式碼

fun main(args: Array<String>) {
    val a = arrayOf(1, 32, 2, 23, 5, 234, 12, 978, 2, 2, 0, 4)

    var h=1
    while (h<a.size/3){
        h=3*h+1
    }

    while (h>=1){
        for (i in h until a.size){
            for(j in i downTo h step h){
                if(a[j]>a[j-h]){
                    val t=a[j]
                    a[j]=a[j-h]
                    a[j-h]=t
                }
            }
        }
        h /= 3
    }
    a.forEach { print("$it ") }
}
複製程式碼
『演算法』之 初級排序演算法總結

希爾排序的詳細軌跡
圖片來自 algs4.cs.princeton.edu

『演算法』之 初級排序演算法總結

希爾排序的可視軌跡
圖片來自 algs4.cs.princeton.edu

相關文章