排序算法學習(2)-希爾排序

希爾排序

希爾排序是簡單排序中插入排序的一種更高效的改進版本,可是直接插入排序是穩定的,希爾排序是不穩定的。java

其基本思路是:算法

  • 假設數組長度爲 n ,假設初始步長爲 k (1<k<n ,k=1即爲直接插入排序)
  • 根據步長 k 對數組進行分組,第一組爲:第 1 個數、第 1+k 個數 ... ,第二組爲:第 2 個數、第 2+k 個數... ,...... ,第 k 組爲:第 k 個數、第 k+k 個數 ...
  • 如此對每一個組進行插入排序;接下來,將步長設爲 k/2 ,一樣的進行分組,對每一組進行插入排序
  • 重複這個步驟直到步長爲 1 ,對整個數組進行一次插入排序後,排序完成。

示意圖

ShellSort_1.png

在示例中先對數組進行 4 分組,每組進行一次插入排序,再進行 2 分組的插入排序,最後步長爲 1 ,進行一次普通的插入排序。數組

雖然在示意圖中對每一分組單獨進行了插入排序,但這只是便於理解,實際上,能夠在數組的一次遍歷過程當中對全部分組進行插入排序。下圖是 4 分組插入排序的示意圖。spa

ShellSort_2.png

示例代碼

public class ShellSort {
    public static void sort(int[] arr) {
        for (int i = arr.length >> 1; i > 0; i >>= 1) {
            insertSort(arr, i);
        }
    }
    private static void insertSort(int[] arr, int delta) {
        for (int i = delta; i < arr.length; i ++) {
            int j = i;
            int temp = arr[j];
            while (j >= delta && temp < arr[j-delta]) {
                arr[j] = arr[j-delta];
                j-=delta;
            }
            arr[j] = temp;
        }
    }
}

步長的設置

毫無疑問,希爾排序與直接插入排序最大的不一樣在於設置了步長序列,在上面的代碼中,設置的步長序列直接是上一個步長除以 2 直到步長爲 1 ,但實際上,效率最高的步長序列並不是是上述結構,不一樣的序列的排序快慢不一樣,能夠閱讀相關資料,得知其餘步長的具體細節。code

時間複雜度和空間複雜度

因爲不一樣步長會影響到排序算法的時間複雜度,因此沒法肯定算法的平均時間複雜度,不過根據維基百科上所說其時間複雜度在 $O(nlog_2n)$ 和 $O(n^2)$ 之間。blog

而空間複雜度,因爲沒有用到額外空間,所以其空間複雜度爲 $O(1)$ 。排序

穩定性

雖然直接插入排序是穩定的,可是因爲希爾排序經過步長分割數組,在分組排序中其天然順序會被打亂,所以他是不穩定排序。ip

相關文章
相關標籤/搜索