1. 程式人生 > >排序算法---希爾排序

排序算法---希爾排序

直接 while new mage div style shells i++ 命令

在介紹了前面的三種基本算法之後,今天說說另一種稍微高級一點的算法--希爾排序

希爾排序是按照其設計折希爾(Donald Shell)的名字命令,它基於插入算法,在插入算法上做了改造,那麽插入算法有什麽特點呢,我們回想一下:

1. 插入排序在已經排好序的序列上效率非常高,時間復雜度O(n),但是在最壞的情況下時間復雜度為O(n2)

2. 插入排序在做移動的時候效率是非常低的,因為每次只能移動一位

基本思想:

先選取小於N的整數d1,把數組中所有距離為d1的倍數值歸為一組,先後在各組中進行插入排序,然後選擇第二個整數d2<d1作為第二個增量,在將整個數列距離為d2的整數倍歸為一組,再在組內進行插入排序,知道增量為1,至此整個數據將會排好順序;

希爾排序算法使用的gap也就是d1、d2.。。為d1 = lenght/2 d2=d1/2 ,最好我們會說明其他的更高效的分組閥值

希爾排序圖:

技術分享圖片

1. 在圖中我們可以看到,未排序的原始數組長度為10,第一次叠代我們選擇gap為length/2=5,

2. 則我們將整個數組分為5組,在圖中我們可以清晰看到(8,3)為一組(9,5)為一組,以此類推

3. 我們在每組內進行插入排序,則排序後的結果就是第三個圖中所示,之後我們在繼續分組,gap = 5/2 = 2,表示整個數列被分成兩組

4. 繼續使用直接插入排序,對兩組數據進行直接插入排序,以此執行分組,排序,再分組、再排序,知道gap=1,則整個數組排序完成

那麽實現一下代碼:

/**
 * 希爾排序
 * 將數組分成N組,N組內使用插入排序,經過m次後,數須有序
 * 希爾排序的曾量序列對排序性能致關重要,我們采用的N/2這種曾量,其最終時間復雜度還是o(n2)
 * 可以使用其他增量比如 Hibbard,可以使時間復雜度縮小到O(n3/2),Sedgewick時間復雜度O(n4/3)
 */
public class ShellSort {

    public static void shellsort(int[] arr) {
        long start = System.currentTimeMillis();
        
//使用length/2的gap值,知道gap=1 for (int gap = arr.length / 2; gap > 0; gap /= 2) { for (int i = gap; i < arr.length; i++) { int j = i; // 使用直接插入排序,依次對數列中每個元素和該元素同組元素進行直接插入排序 while (j - gap >= 0 && arr[j] < arr[j - gap]) { int tmp = arr[j]; arr[j] = arr[j - gap]; arr[j - gap] = tmp; j -= gap; } } } System.out.printf("直接插入算法\t運行時間%dms\n", (System.currentTimeMillis() - start)); } public static void main(String[] args) { int data_len = 10000; int[] data = new int[data_len]; Random rd = new Random(); for (int index = 0; index < data_len; index++) { data[index] = rd.nextInt(10000); } System.out.println("生成數據完成"); shellsort(data); showData(data); } public static void showData(int[] data) { for (int item : data) { System.out.printf("%d,", item); } System.out.println(); } }

在代碼中我進行了簡單註釋,從gap開始遍歷所有數據元素,讓該元素和同組元素進行直接插入排序,知道gap=1

從直觀的感覺上什麽決定了希爾排序的性能呢,那就是我們選擇gap的算法,代碼我們使用了 gap = length/2 的初始值,該算法並非是最優的,但是很好理解,也希爾排序推薦的,但是我們可能追求極至,那麽可以網上查一下其他gap生成算法,使用最多的應該是

註釋中提到的 Hibbard

排序算法---希爾排序