希爾排序分析實現

算法思想:

希爾排序又叫縮小增量,也是一種插入排序。希爾排序中有一個步長,通過這個步長將數組分化爲步長個序列,然後分別對這些序列進行直接插入排序,然後改變步長,重複操作,直到步長爲1,而此時數組基本有序,很快。步長的取法一般是開始爲(數組長度/2),然後是對步長一直除2直到步長爲1。

算法運行過程圖:

這裏寫圖片描述

代碼實現思路:

  • 思路1:按照算法思想,有一個循環步長的循環,然後對某個步長劃分的那些子序列進行插入排序。
  • 思路2:相對於上面的每次直接插入排序從序列的第一個元素開始,直到該序列的最後一個元素,其實直接插入排序時可以從下標爲步長的元素開始,然後相當於混合這對劃分的每個序列進行直接排序,直接排序其實是從序列的第2個元素開始,然後每次判斷是否比該序列的前一個數小,如果小的話就進行插入操作。見shellSort1()註釋。

優化方法:

  1. 優化步長。有點麻煩。
  2. 優化直接插入排序。見shellSort()註釋。

時間複雜度:

根據步長的不同取法不一定。有點複雜。

空間複雜度:

O(1)

穩定性:

不穩定。
在子序列的插入過程中可能打亂穩定性。

代碼實現:

package sort;

/**
 * @作者:dhc
 * @創建時間:20:41 2018/8/14
 * @排序方法:希爾排序
 * @時間複雜度:有點複雜。
 * @空間複雜度:O(1)
 * @穩定性:不穩定。
 */
public class ShellSort {
    /**
     * 直接插入排序說明:這裏直接插入排序因爲有幾種不同的寫法,1,常規的先找插入位置,在後移 插入。2,對1插入位置查找採用二分查找。3,不用先查找
     * 位置,將兩個循環合成一個,直接後移。4,同3一樣,用一個循環,不過用交換來實現。因此希爾排序也可有對應的寫法。採用不同的寫法,對於希爾排序的結果
     * 也稍有點點優化。
     * 步長說明:取數組長度的一半,然後循環取一半直到步長爲1.
     * @param nums
     */
    public static void shellSort(int[] nums) {
        int tem = 0;
        for(int ss = nums.length/2;ss >= 1; ss /= 2){
            for (int k = 0; k < ss; k++) {
                //直接插入排序
                for(int i = ss;i < nums.length;i += ss){
                    tem = nums[i];
                    int j = i;
                    for(j = i;j > 0 && nums[j - ss] > tem;j -= ss){
                        nums[j] = nums[j-ss];
                    }
                    nums[j] = tem;
                }
            }
        }
    }

    /**
     * 優化循環次數
     * 相對於上面的每次直接插入排序從序列的第一個元素開始,直到該序列的最後一個元素,其實可以直接插入排序時可以從下標爲步長的元素開始,然後
     * 相當於混合這對劃分的每個序列進行直接排序,直接排序其實是從序列的第2個元素開始,然後每次判斷是否比該序列的前一個數小,如果小的話就進行
     * 插入操作。
     * @param nums
     */
    public static void shellSort1(int[] nums) {
        int tem = 0;
        for(int ss = nums.length/2;ss >= 1; ss /= 2){
            //這裏取i等於步長,相當於直接進入插入排序,用劃分的第一個序列的第二個元素開始,當i+1時,如不步長不爲1,則相當於
            // 進入下一個序列的插入排序,這個i+1同樣是第二個元素,直到i+ss,有進入第一個序列的第三個數,循環往復,直到數組最後
            for (int i = ss; i < nums.length; i++) {
                //這裏判斷是否比該序列的前一個數小,如果小的話就要插入到該序列的前面
                if(nums[i] < nums[i - ss]){
                    tem = nums[i];
                    int j = i;
                    for(j = i - ss;j >=0 && nums[j] > tem;j-=ss){
                        nums[j+ss] = nums[j];
                    }
                    nums[j + ss] = tem;
                }
            }
        }
    }
    public static void main(String[] args) {
        int[] nums = new int[]{5,4,3,2,1,1,7,6};
        shellSort1(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i]+" ");
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章