重温算法导论(四) 希尔排序

希尔排序,就是插入排序的改进,具体改进的办法,就是利用增量对排序队列进行划分,再使用插入排序,如以下:

重温算法导论(四) 希尔排序_第1张图片


利用分组排序后,再进行最后的排序

其伪代码为:

for path=0 to length_dlta
    for i=path to n   //一趟分段直接插入排序
        temp = data[i]
        j=i-path
        while j>=0 and temp

实现代码如下:C++实现

template void ShellSortT(T a[], int iLength)
{
	int increment = iLength / 2;
	int cols[] = {1391376, 463792, 198768, 86961, 33936, 13776, 4592,
		1968, 861, 336, 112, 48, 21, 7, 3, 1};
	for(int k = 0 ; k< 16; k++)
	{
		//int increment  = cols[k];
		for(int i= increment; i< iLength; i++)
		{
			T key = a[i];
			int j = i-increment;
			while( j>=0  && a[j] > key)
			{
				a[j+increment] = a[j];
				j = j - increment;
			}
			a[j+increment] = key;
		}
		increment = increment / 2;
	}
}
int main(int argc, char* argv[])
{
	int iData[5] = {6,8,5,7,4};
	ShellSortT(iData, 5);
}

关于时间复杂度,收到递增量的影响

增量序列

  1. 希尔序列:[1,2,4,8,16,32,...,2k,...][1,2,4,8,16,32,...,2k,...] 
    该序列由希尔本人提出。这种序列在最坏情况下的时间复杂度为O(n2)O(n2)。原因很复杂,可以参考《数据结构 邓俊辉》著。
  2. PS序列:[1,3,7,15,31,63,...,2k1,...][1,3,7,15,31,63,...,2k−1,...] 
    这个序列中各项两辆互素。采用这个序列,希尔排序的效率可以改进至O(n3/2)O(n3/2),其中n为排序规模。

  3. Pratt序列[1,2,3,4,6,8,9,12,16,...,2p3q,...][1,2,3,4,6,8,9,12,16,...,2p3q,...] 
    其中各项除2 和3 外均不含其它素数因子。采用Pratt序列,希尔排序时间复杂度至多为O(nlog2n)O(nlog2n)

  4. Knuth序列(没找到出处) 
    Knuth提出了他自己的增量序列,遵循公式(3k-1)/ 2或[1,4,14,40,121,…]

算法分析

空间复杂度: 仅使用了常数个辅助单元,因而空间复杂度为O(1)O(1)。 
时间复杂度:ShellSort排序准确的说是一类排序。当使用不同的增量序列进行布置时,效率差异极大。这个int [] cols数组的选取(增量序列)选取非常的关键,究竟什么样的布置方案(增量序列cols)才是最好,目前还是一个数学难题,所以时间复杂度分析也比较困难,前人对这方面的研究也比较多,可以查阅相关论文。这里仅仅可以讨论下PS,Pratt和Donald Shell序列的复杂性。 对于Shell的序列,复杂度是O(n2)O(n2),而对于Pratt的序列,它是O(nlog2n)O(nlog2n)。 PS序列,其中复杂性是O(n3/2)O(n3/2)

稳定性:(不稳定) 
希尔排序的关键是 把排序序列 用相隔某个“增量” 将元素组成一个“列”,每个“列”各自进行插入排序,从而实现元素的跳跃式移动,使得排序效率提高。当相同的关键字被划分到不同的“列”时,可能会改变它们之间的相对次序,因此希尔排序是一个不稳定的算法。


文章中引用到:

引用1:Shell-Sort 增量排序算法 总结

引用2:   点击打开链接算法导论------ShellSort希尔排序

你可能感兴趣的:(算法)