通用算法 -[排序算法] -希爾排序

1、算法由來

我們知道,簡單插入排序在數據規模較小數據基本有序時十分高效。
那如果數據規模較大,並且無序時,有什麼樣的方法可以提高簡單插入排序的效率呢?
希爾排序正是爲此而生,它通過構造(1)小規模數據和(2)讓數據基本有序的條件來達到高效排序。

2、算法思想

希爾排序的基本思想是分組進行插入排序。即每次根據增量序列(從大到小)中的一個增量值,將數組劃分成若干組,然後對這若干組分別進行簡單插入排序。直到數組有序位置。
以數組array=[5,7,8,3,1,2,4,6]爲例,希爾算法的具體過程如下:
(1)首先它把較大的數據集合分割成若干個小組(邏輯上分組),然後對每一個小組分別進行插入排序,此時,插入排序所作用的數據量比較小(每一個小組),插入的效率比較高。
在這裏插入圖片描述
圖解算法---希爾排序

可以看出,他是按下標相隔距離爲4分的組,也就是說把下標相差4的分到一組,比如這個例子中a[0]與a[4]是一組、a[1]與a[5]是一組…,這裏的差值(距離)被稱爲增量
圖解算法---希爾排序
(2) 每個分組進行插入排序後,各個分組就變成了有序的了(整體不一定有序)
圖解算法---希爾排序

此時,整個數組變的部分有序了(有序程度可能不是很高)

圖解算法---希爾排序

(3) 然後縮小增量爲上個增量的一半:2,繼續劃分分組,此時,每個分組元素個數多了,但是,數組變的部分有序了,插入排序效率同樣比高。
在這裏插入圖片描述

同理對每個分組進行排序(插入排序),使其每個分組各自有序
圖解算法---希爾排序

(4) 最後設置增量爲上一個增量的一半:1,則整個數組被分爲一組,此時,整個數組已經接近有序了,插入排序效率高
在這裏插入圖片描述

同理,對這僅有的一組數據進行排序,排序完成

3、代碼實現

希爾排序分組實現:

template<typename T>
void shellSort(T* array,int len){
	//對數組進行分組,最開始的增量(gap)爲數組長度的一半;
	for (int gap = len / 2; gap >= 1; gap = gap / 2){
		//對以gap爲增量形成的分組進行插入排序
		for (int i = gap; i < len; i++){
			insertSort(array, i, gap);
		}
	}
}

組內進行插入排序實現:

template<typename T>
void insertSort(T* array, int i, int gap){
	/*
	將array[i]插入到所在分組的正確位置上;
	array[i]所在的分組:
	...array[i-gap*2],array[i-gap],array[i],array[i+gap],array[i+gap*2]...
	*/
	
	/*寫法1:
	T inserted = array[i];
	int j = i - gap;
	while (j >= 0 && inserted < array[j]){
		array[j + gap] = array[j];
		j -= gap;
	}*/

	/*寫法2:*/
	T inserted = array[i];
	int j;
	for (j = i - gap; j >= 0 && inserted < array[j]; j -= gap){
		array[j + gap] = array[j];
	}
	array[j + gap] = inserted;

}

4、算法分析

  • 時間複雜度:希爾排序的複雜度和增量序列是相關的。
    {1,2,4,8,...}\{1,2,4,8,...\}這種序列並不是很好的增量序列,使用這個增量序列的時間複雜度(最壞情形)是O(n2)O(n^2),Hibbard提出了另一個增量序列{1,3,7...,2k1}\{1,3,7,...,2^k-1\},這種序列的時間複雜度(最壞情形)爲O(n1.5)O(n^{1.5}),Sedgewick提出了幾種增量序列,其最壞情形運行時間爲O(n1.3)O(n^{1.3}),其中最好的一個序列是{1,5,19,41,109,...}\{1,5,19,41,109,...\}
  • 空間複雜度:O(1)O(1)
  • 穩定性:簡單插入雖是穩定的,但希爾排序是不穩定的,詳細原因見下圖。
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章