java、Go實現希爾排序

1. 希爾排序

上篇文章我們講述了插入排序,其效率高於冒泡以及選擇排序,但是插入排序有一個問題就是如果數組中較小的數字在後方,那麼數組需要移動的次數是很多的,於效率而言是不好的,由此我們引出了希爾排序。
我們可以將數組中較小的數先放在數組靠前的位置,之後再進行插入排序,這樣的話效率肯定會提升,此排序方法就爲希爾排序。

2. 實現思路

將數組分爲若干個小組,每個小組內進行插入排序。分小組的規則爲:定義一個變量,初始時定義其爲數組長度的一半,小組內每個元素相距小組長度個距離,每個小組進行插入排序,當最後只剩下一個小組後,進行插入排序以後就可以得到有序數組。

3. 圖解

–> 第一趟

在這裏插入圖片描述
對應箭頭的顏色即爲同一小組,數組長度爲10,所以第一次被分爲 10/2 個小組,也就是五個。在每個分組內進行插入排序,第一趟排序後:

–>第二趟

在這裏插入圖片描述
如圖,將數組分爲 5/2個小組,也就是2個小組,每個小組的每個元素之間相距爲2,繼續在每個小組內進行冒泡排序

4. 實現思路

  1. 首先我們發現,我們每次需要分小組,每次將小組數量分爲上一次的一半個,所以我們發現這可以使用一個循環進行:
    for(int gap = arr.length/2; gap > 0; gap /= 2)
  2. 之後我們只需要關注每一個小組內的冒泡排序了,這就是輕車熟路了,我們首先需要定義一個循環,來進行每個小組內的插入排序
    for (int i = gap; i < arr.length; i++)
  3. 進行了兩次循環後,我們現在已經分好了組,並且找到了插入排序的需要插入的數據arr[i],那麼我們現在就可以找到其之前的小組內成員,若小於前面的成員,則移位
    int insertIndex = i;
    int insertValue = arr[i];
    while(insertIndex - gap >= 0 && insertValue < arr[insertIndex - gap]){
    arr[insertIndex] = arr[insertIndex - gap];
    insertIndex -= gap;
    }
    arr[insertIndex] = insertValue;
  4. 經過以上步驟,等最後剩下一個小組以後,我們還會進行一次插入排序,相當於對數組進行插入排序,那麼數組就是有序的了,之後gap/2 = 0,不會進入分組的循環,流程結束

5. 代碼

java版本
 private static void shellSort(int[] arr){
        for (int gap = arr.length/2; gap > 0; gap /= 2){
            for (int i = gap; i < arr.length; i++){
                int insertIndex = i;
                int insertValue = arr[i];
                while(insertIndex - gap >= 0 && insertValue < arr[insertIndex - gap]){
                    arr[insertIndex] = arr[insertIndex - gap];
                    insertIndex -= gap;
                }
                arr[insertIndex] = insertValue;
            }
        }
    }

初步測試(10個數據):

 public static void main(String[] args) {
        int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
        shellSort(arr);
        System.out.println(Arrays.toString(arr));
    }

輸出:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

速度測試(80000數據):

 public static void main(String[] args) {
        int[] arr = new int[80000];
        Random random = new Random();
        for (int i = 0; i < arr.length; i++){
            arr[i] = random.nextInt(800000);
        }
        System.out.println(System.currentTimeMillis());
        shellSort(arr);
        System.out.println(System.currentTimeMillis());
        System.out.println(Arrays.toString(arr));
    }

輸出:

1585650645547
1585650645559
//下面打印的數組就不復制了,太長了,可以自己粘貼代碼測試,不過最好還是自己寫一遍

結論:
可以看到,希爾排序可太快咯,比起插入排序的效率已經高了三四層樓那麼高了

Go語言版本
//希爾排序
func shellSort(arr []int){
	//將數組分小組
	for gap := len(arr)/2; gap > 0; gap /= 2 {
		//每個小組進行插入排序
		for i := gap; i < len(arr); i++ {
			insertIndex := i;
			insertValue := arr[i];
			for {
				if (insertIndex - gap < 0 || insertValue >= arr[insertIndex - gap]){
					break
				}
				arr[insertIndex] = arr[insertIndex - gap]
				insertIndex -= gap
			}
			arr[insertIndex] = insertValue
		}
	}
}

速度測試(80000數據):

func main(){
	arr := make([]int, 80000)
	t := time.Now()
	fomat := t.UnixNano()
	rand.Seed(fomat)
	for i := 0; i < len(arr); i++{
		arr[i] = rand.Intn(80000)
	}
	t1 := time.Now()
	shellSort(arr)
	t2 := time.Since(t1)
	fmt.Println(t2)
	// arr := make([]int, 8)
	// queen8(arr, 0)
	// fmt.Println(count)
}

結果:

8.9435ms
複雜度分析

希爾排序複雜度比較複雜,這個就不討論了哈哈哈,反正不是O(n^3)


以夢爲馬,不負韶華

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