1. 程式人生 > >八大排序———希爾排序

八大排序———希爾排序

  希爾排序(Shell's sort)是插入排序的一種 又稱為“縮小增量排序”(Diminishing Increment Sort),是直接插入排序演算法的一種更高效的改進版本。希爾排序是不穩定的排序演算法。

  希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量的逐漸減少,每組包含的關鍵字越來越多,當增量減少至1時,整個檔案恰被分為一組,演算法終止。

    希爾排序是基於插入排序的一下兩點性質而提出改進方法的:

1.插入排序在對幾乎已經排好序的資料操作時,效率高,既可以達到線性排序的效率。

2.但插入排序一般來說是低效的,因為插入排序每次只能將資料移動一位。

一:基本思想

  先取一個小於n的整數d1作為第一個增量,把檔案的全部記錄分組。所有距離為d1的倍數的記錄放在同一個組中。先在各組中進行直接插入排序;然後取第二個增量d2<d1重複上述的分組和排序,直至所取的增量d = 1,即所有的記錄放在同一組中進行直接插入排序為止。

    實質:分組插入方法

  比較相隔較遠距離(稱為增量)的數,使得移動時能夠跨越多個元素,則進行一次比較就可能消除多個元素的交換。

一般的初次取序列的一半為增量,以後每次減半,直到增量為1。

 二:演示過程 

三:程式碼解析

#include<iostream>
using namespace std;

template<typename T>
void shellinsert(T arr[],int len,int grp)//O(n)
{
		int i = grp;
		int j = 0;
		T tmp = T();
		for(i=grp;i<len;++i)
		{
				tmp = arr[i];
				for(j = i-grp;j>=0;j-=grp)
				{
						if(arr[j]>tmp)
						{
								arr[j+grp] = arr[j];
						}
						else
								break;
				}
				arr[j+grp] = tmp; 
		}
}
template<typename T>
void shell(T arr[],int len)
{
		for(int div = len/2;div>0;div/=2)//時間複雜度為O(log n)
		shellinsert(arr,len,div);

}

int main()
{
		int arr[] = {15,48,67,9,45,13,16,9,99,13};
		int len = sizeof(arr)/sizeof(arr[0]);
		shell1(arr,len);
		for(int i= 0;i<len;++i)
		{
				cout<<arr[i]<<" ";
		}
		cout<<endl;
		return 0;
}

四:穩定性分析

  由於多次插入排序,我們知道一次插入排序是穩定的,不會改變相同元素的相對順序,但在不同的插入排序過程中,相同的元素可能在各自插入排序中移動,最後其穩定性就會被打亂,所以shell排序是不穩定的。

五:時間複雜度

  演算法的平均複雜度為 O(n^1.3),演算法的最壞的時間複雜度為O(n^2),最好的時間複雜度為O(n),空間複雜度為O(1)。

六:演算法分析

  不需要大量的輔助空間,希爾排序是基於插入排序的一種演算法,在此演算法之上增加了新的特性,提高了效率。希爾排序的時間複雜度與增量序列的選取有關,例如希爾增量的時間複雜度為O(n^2),而Hibbard增量的希爾排序的時間複雜度為O(n^1.5),當資料量相當大的時間,其演算法的效率不如快排快,因此中等大小的資料量適用於希爾排序,希爾排序在最壞和平均的情況下執行效率差不多,而快速排序的最壞和平均的情況下其相差比較大,所以,幾乎任何排序工作在開始時都可以用希爾排序,如果在實際中,其速度不能滿足我們的要求我們在使用快排。

shell演算法的效能與所選取的分組長度序列有關。