圖文並茂!一文教你掌握十大排序算法之希爾排序(增量排序)

如果還沒真正瞭解過直接插入排序的讀者可先去看看直接插入排序的原理及實現:一文掌握直接插入排序

1. 希爾排序原理介紹

希爾排序是直接插入排序的一種更高效的改進版本。但是希爾排序是一種非穩定排序算法。

希爾排序是基於插入排序的以下兩點性質而提出改進方法的:

  1. 插入排序在對幾乎已經排好序的數據操作時,效率高,即可以達到線性排序的效率;
  2. 插入排序一般來說是非常低效的,因爲插入排序每次只能將數據移動一位;

希爾排序的原理:將一個待排序的數組分爲若干個以Step爲增量的若干個子序列,對這若干個子序列依次進行直接插入排序,在每一次排序完以後的Step呈遞減趨勢變化,當Step爲1時,此時的序列已經基本有序,對整個序列進行直接插入排序。當增量爲0時代表數組已經有序。

2. 算法流程演示:

以下圖爲例:待排序數組爲:[3, 5, 1, 2, 4, 6, 7]

1. 增量Step取數組長度的一半即 7 / 2 = 3,意思就是每3個增量的元素被視爲同一個序列當中

(我們主觀邏輯上的序列,本質上還是隻有一個數組)

(index = 0,index = 3, index = 6)三個元素組成一個序列:[3, 2, 7]

(index = 1,index = 4,index = 7(超出數組長度))的兩個元素組成一個序列:[5, 4]

(index = 2,index = 5)的兩個元素組成一個序列:[1, 6]

我們對這三個序列進行直接插入排序,排序完成後各個子序列的狀態是:[2, 3, 7],[4, 5],[1, 6]

從原序列來看,排序後的序列爲:[2, 4, 1, 3, 5, 6, 7],此時看到數組已經大致有序了,較大的數都在數組靠右的位置,較小的數都在數組靠左的位置。

2. 增量以原來的1/2遞減,即Step = Step >> 1 = 3 >> 1 = 1,此時增量爲1,待排序的序列爲整個數組序列[2, 4, 1, 3, 5, 6, 7]

使用直接插入排序對整個序列進行排序,具體流程就不演示了,我們可以發現只需要移動三次就可以完成排序了,分別是1和4交換位置,1和2交換位置,3和4交換位置,希爾排序在面對數據量較大的數組時表現出來的速度會比直接插入排序快很多。

3. Step >> 1 = 0,表明數組已有序,排序完成。

3. 代碼實現

/**
 * @author Zeng
 * @date 2020/2/29 23:04
 */
public class 希爾排序1 {

    public static void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void shellSort(int[] arr){
        int step = arr.length / 2;
        while (step != 0){
            System.out.print("增量爲:"+step+";");
            System.out.print("數組的子序列分爲:");
            for (int i = 0; i < step; i++){
                System.out.print("{ ");
                for (int j = i; j < arr.length; j+=step){
                    System.out.print(arr[j]+" ");
                }
                System.out.print("};");
            }
            //核心算法,本質上是直接插入排序
            for (int i = 0; i < step; i++){
                int index = i + step;
                while (index < arr.length){
                    int current = arr[index];
                    int position = index - step;
                    while (position >= 0 && arr[position] > current){
                        swap(arr, position, position + step);
                        position -= step;
                    }
                    index += step;
                }
            }
            step = step >> 1;
            System.out.println();
        }
    }

    public static void main(String[] args) {
        int[] arr = new int[]{3, 5, 1, 2, 4, 6, 7};
        shellSort(arr);
        System.out.print("排序結果:");
        for (int i : arr) {
            System.out.print(i+" ");
        }
    }

}
//增量爲:3;數組的子序列分爲:{ 3 2 7 };{ 5 4 };{ 1 6 };
//增量爲:1;數組的子序列分爲:{ 2 4 1 3 5 6 7 };
//排序結果:1 2 3 4 5 6 7 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章