4. 進階排序算法——希爾排序(golang)


希爾排序


前言

插入排序在某些情況下,效率是很高的。

比如我們的記錄本身就是基本有序的,只需要少量的插入操作。

再比如,記錄少的時候,插入排序效率的優勢也是很明顯的。

可是現實中,哪有那麼理想的情況啊[>_<]

沒有環境,那我們就要自己創造啊!!!


基本有序:

所謂的基本有序就是小的關鍵字在前面,大的基本在後面,不大不小的基本在中間。





希爾排序的思想核心


關鍵詞: 步長分組


我們首先根據一定的步長,將原有的記錄進行分組

在分組內,使用插入排序把分組變成有序。

然後調整增量,繼續對分組做插入排序處理。

直至最後步長變爲1,此時整個記錄已經基本有序了,再進行少量的插入操作,就可以把整個記錄變成有序。



舉個例子:

在這裏插入圖片描述




代碼實現


func shellSortStep(arr []int, start int, gap int) []int {

	// 數組長度
	length := len(arr)

	// 插入排序的變種
	for i := start + gap; i < length; i += gap {

		// 備份待插入的數據
		backup := arr[i]

		// 初始化待插入位置
		j := i - gap

		// 待插入數據,小於前面的數據
		for j >= 0 && backup < arr[j] {
			// 從前往後移動
			arr[j+gap] = arr[j]
			j -= gap
		}

		arr[j+gap] = backup
	}

	return arr
}

func ShellSort(arr []int) []int {

	// 數組長度
	length := len(arr)

	// 數組爲空或者只有一個元素
	if length <= 1 {
		return arr
	}

	// 步長
	gap := length / 2

	for gap > 0 {

		// 處理每個元素的步長
		for i := 0; i < gap; i++ {
			shellSortStep(arr, i, gap)
		}
		gap /= 2
	}

	return arr
}


題外話:增量怎麼確定?

有人說,按照Knuth序列,應該是這樣的:

 // 如果h最終爲1
h = 1 

 // 則h的計算公式爲,同時h不應該大於1/3,否則就比整個數組長度還要大了
h = 3*h - 1


Kunth序列版代碼實現


func shellSortStep(arr []int, start int, gap int) []int {

	// 數組長度
	length := len(arr)

	// 插入排序的變種
	for i := start + gap; i < length; i += gap {

		// 備份待插入的數據
		backup := arr[i]

		// 初始化待插入位置
		j := i - gap

		// 待插入數據,小於前面的數據
		for j >= 0 && backup < arr[j] {
			// 從前往後移動
			arr[j+gap] = arr[j]
			j -= gap
		}

		arr[j+gap] = backup
	}

	return arr
}

func ShellSort(arr []int) []int {

	// 數組長度
	length := len(arr)

	// 數組爲空或者只有一個元素
	if length <= 1 {
		return arr
	}

	// 步長
	gap := 1
	for gap <= length/3 {
		gap = gap*3 + 1
	}

	for gap > 0 {

		// 處理每個元素的步長
		for i := 0; i < gap; i++ {
			shellSortStep(arr, i, gap)
		}
		gap = (gap - 1) / 3
	}

	return arr
}


時間複雜度

希爾排序的時間複雜度是:O(n^(1.3—2))

爲什麼是個區間呢?

因爲時間複雜度和增量的選擇有關,選擇不同的增量會有不同的效果。

但不論怎麼說,希爾排序的性能要好於直接排序的O(n^2)。



穩定性

由於希爾排序在排序的過程中,記錄時跳躍式的移動,所以希爾排序是一種不穩定排序算法

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