排序算法(六)————希爾排序

希爾排序是對直接插入排序的一種改進,我們都知道直接插入排序在元素次序規則,數量較少時效率是最高的,而希爾排序恰巧合理的利用了這兩點,對冒泡排序進行了改進,希爾排序的核心在於分組,什麼是分組呢:

如下有10個元素:
12,15,8,66,24,55,34,99,3,10
我們假如要對其進行希爾排序,我們第一步要做的就是對其進行分組,那麼分組依據是什麼呢?

我們最常用的分組依據是lenth/2得到步長,何爲步長?說通俗一點就是同一組元素之間的間隔大小,拿上面那個數列爲例,10/2=5,當步長爲5時,我們的元素被分成了5組分別爲:

【12,55】 【15,34】 【8,99】【66,3】 和【24,10】

由此可見,步長實際上就是每一組相鄰兩個元素之間的位置差,比如第一組的12位置爲0,55位置爲5,他們位置之差就是步長5。

當然,分組實際上並不是真的就將這些元素拿出來分別裝到五個數組裏,而是一種邏輯分組,他們還是在原來的數組,原來的位置,只是在邏輯上把他們分到了一組而已。
分組完後我們要做什麼呢?接下來就是分別在組內進行直接插入排序,排序完成後將步長再次減半,這樣一個小組裏元素會變多,並且每一個小組中元素會變得相對有序一些,一直到步長爲1,這時候整個程序就變成了一個我們常用的插入排序,最後排序完成後即爲結果。
這裏需要注意的是我們在邏輯實現的時候並不是對這些組依次分別進行一個插入排序,我們是這樣進行的:

每組第一個元素可以不用考慮,因爲一個元素的時候是有序的。
從每組第二個元素開始依次進行插入排序,實現數列中每組元素中第一第二個元素有序化。
開始進行各個組第三個元素的排序,實現各個組內前三個元素的有序化。

一開始我在學習希爾排序時,我理解成了先把第一小組所有元素排好,再排第二小組所有元素,…
然後在看代碼時一臉懵逼,完全不知道他們寫的邏輯是什麼,後來我終於反應過來並不是這樣的,排序順序是循環按照元素順序着來的,先排所有小組第二個元素,再排所有小組第三個元素,…大家一定要理解這一塊,這是比較容易把思路帶到溝裏的一點,說白了就是排序也是從前往後按照原數列順序依次排的,並不是按照各個小組整體依次排序的。

下面我給出C語言實現的代碼,實際上代碼並不複雜,中間一段和插入排序很像,只是向前找元素的時候不是減一,而是減步長,因爲你上一個元素和你現在要比較的值的位置差爲一個步長,並且一開始所在位置位於r處,因爲前r個元素是每個組第一個元素,他們實際上在每個組裏本身就是有序的。

代碼實現如下(代碼經過測試,可以直接使用):

void shell(int arr[], int len);

void main()
{
	int arr[10] = {12,44,1,23,67,16,170,233,99,43};
	shell(arr,10);
	for (int i = 0; i < 10;i++)
	{
		printf_s("%d\n", arr[i]);
	}
}

void shell(int arr[],int len)
{
	int i;
	int r;
	//步長不斷減小
	for (r = len / 2;r >= 1;r /= 2)
	{
		for (i = r;i < len;i++)
		{
			int key = arr[i];
			while (arr[i-r]>key && i>0)
			{
				arr[i] = arr[i - r];
				i = i - r;
			}
			arr[i] = key;
		}
	}
	
}

希爾排序時間複雜度和我們選擇的增量有關,目前最好的時間複雜度爲:O(n^1.3)
關於其時間複雜度的最優解,是一個尚未解決的數學難題,就看你了,騷年。

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