決勝經典算法之希爾排序

習題答案

題目回顧

在上一篇文章中,咱們以數列從小到大排列爲例,講了插入排序。結尾處的思考題以下:java

若是要實現從大到小排列,上述代碼該作如何修改呢?算法

一樣,要解答這個問題也很簡單,下面放上答案。shell

答案

咱們知道,從小到大排序時,實際上就是逐個比較大小,把更小的元素向前移。同時,把整個數組分爲「已排序」和「未排序」兩個區域。要解決從大到小排序時,具體作法相似,只需將更大的元素向前移便可。參考以下代碼:編程

public static void insertSort(int[] arr) {
    int temp;
    int j;
    for (int i = 1; i < arr.length; i++) {
        for (j = i - 1; j >= 0; j--) {
            if (arr[i] < arr[j])
                break;
        }
        if (j != i - 1) {
            temp = arr[i];
            for (int k = i; k > j + 1; k--) {
                arr[k] = arr[k - 1];
            }
            arr[j + 1] = temp;
        }
    }
}

怎麼樣,你答對了嗎?數組


本篇文章的內容是講第四種排序方法——希爾排序。
仍是以前的問題:編程語言

問題挑戰

現有以下數字:   
3,44,38,5,47,15,36,26,27,2,46,4,19,50,48   
一共15個數字,請將其從小到大依次排列。code

算法解析

希爾排序,又被稱爲縮小增量排序。它和插入排序有相同之處,也有所區別——希爾排序會優先比較距離較遠的元素。
歸納地講,希爾排序就是先取一個正整數,這個正整數暫定爲3。把全部序號相隔這個數值的數組元素放一組,組內進行直接插入排序;而後再把這個正整數作自減一運算,重複上述分組和排序操做;直至這個正整數的值爲1,即全部記錄放進一個組中排序爲止。
爲何咱們把步長(即上文中的「正整數」)初始值定位3呢?由於該排序算法最複雜的就是該步長的肯定。按照自減一再排序的操做,整個排序過程只須要3次排序便可完成。
是否是以爲有點不太好理解?下面咱們分步拆解:blog

詳細步驟

下面讓咱們來分步驟拆解整個希爾排序:排序

  1. 選擇一個增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
  2. 按增量序列個數 k,對序列進行 k 趟排序;
  3. 每趟排序,根據對應的增量 ti,將待排序列分割成若干長度爲 m 的子序列,分別對各子表進行直接插入排序。僅增量因子爲 1 時,整個序列做爲一個表來處理,表長度即爲整個序列的長度。

希爾排序的思想是:先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,待整個序列中的記錄基本有序時,再對全體記錄進行依次直接插入排序。整個流程以下圖(以增量爲3爲例)所示:element

希爾排序流程圖

僞代碼

接下來,咱們使用僞代碼實現上述過程

input: an array a of length n with array elements numbered 0 to n − 1
inc ← round(3)
while inc > 0 do:
for i = inc .. n − 1 do:
temp ← a[i]
j ← i
while j ≥ inc and a[j − inc] > temp do:
a[j] ← a[j − inc]
j ← j − inc
a[j] ← temp
inc ← round(inc--)

Java代碼實現

接下來,咱們使用Java編程語言實現上述算法。

public static void shellSort(int[] arr) {
    int gap = arr.length;
    while (true) {
        // gap 表示增量,這裏以數組長度的一半爲例
        gap /= 2;
        for (int i = 0; i < gap; i++) {
            for (int j = i + gap; j < arr.length; j += gap) {
                int temp = arr[j];
                int k = j - gap;
                while (k >= 0 && arr[k] > temp) {
                    arr[k + gap] = arr[k];
                    k -= gap;
                }
                arr[k + gap] = temp;
            }
        }
        if (gap == 1)
            break;
    }
}

思考題

1. 若是要實現從大到小排列,上述代碼該作如何修改呢?

思考題答案依舊會在下篇連載中公佈,你們加油哦!

相關文章
相關標籤/搜索