排序算法之希尔排序

排序算法之希尔排序

简介

之前介绍的几种排序算法,简单选择排序、直接插入排序,它们的时间复杂度都是 O ( n 2 ) O(n^2) O(n2)。实际上在早期很长一段时间内,普遍认为排序算法的效率不会高于 O ( n 2 ) O(n^2) O(n2),直到希尔排序算法的出现才打破了这一认知。希尔排序是第一批冲破二次时间界( O ( n 2 ) O(n^2) O(n2))的算法之一。它通过比较相距一定距离的元素来排序,各趟比较所使用的距离随算法的进行而减小,直到比较相邻元素为止。因此,希尔排序也称缩减增量排序

希尔排序通过使用一个增量序列 h 1 h_1 h1 h 2 h_2 h2,…, h t h_t ht,将待排序元素序列分为若干个子序列。然后对这些子序列进行排序,使其 a [ i ] < = a [ i + h k ] a[i]<=a[i+h_k] a[i]<=a[i+hk],此时所以相隔 h k h_k hk的元素都被排序,称为序列是 h k h_k hk排序的。如下图。
在这里插入图片描述
下面我们继续通过代码进行逐步讲解,完整代码见https://github.com/kfcyh/sort/tree/master/shellsort。

代码讲解

void ShellSort(SqList L)
{
	int i, j;
	int increment = L->length;
	do
	{
		increment = increment / 3 + 1;	//增量序列
		for (i = increment + 1; i <= L->length; i++)
		{
			if (L->r[i] < L->r[i - increment])	//需将r[i]插入有序增量子表
			{
				L->r[0] = L->r[i];	//暂存元素
				for (j = i - increment; j > 0 && L->r[0] < L->r[j]; j -= increment)
					L->r[j + increment] = L->r[j];	//元素后移
				L->r[j + increment] = L->r[0];	//插入元素至正确位置
			}
		}
	} while (increment > 1);
}

由代码可知,希尔排序对增量子序列的排序采用插入排序的思想,下面我们通过对序列{9,1,5,8,3,7,4,6,2}进行排序来进行讲解。

  1. 首先是一个 w h i l e while while循环,中止条件是 i n c r e m e n t = 1 increment=1 increment=1。然后初始化增量 i n c r e m e n t = l e n g t h / 3 + 1 increment=length/3+1 increment=length/3+1。内部的外循环 f o r for for每次对增量为 i n c r e m e n t increment increment的子序列进行排序。 i i i i n c r e m e n t + 1 increment+1 increment+1开始,中止条件为 i > l e n g t h i>length i>length。第一次 w h i l e while while循环, i n c r e m e n t = 4 increment=4 increment=4

  2. 第一次 f o r for for循环, i = 5 i=5 i=5 r [ i ] = 3 < r [ i − i n c r e m e n t ] = 9 r[i]=3<r[i-increment]=9 r[i]=3<r[iincrement]=9,交换元素。在这里插入图片描述

  3. 循环继续, i = 6 i=6 i=6 r [ i ] = 7 > r [ i − i n c r e m e n t ] = 1 r[i]=7>r[i-increment]=1 r[i]=7>r[iincrement]=1,不交换元素。

  4. 循环继续, i = 7 i=7 i=7 r [ i ] = 4 < r [ i − i n c r e m e n t ] = 5 r[i]=4<r[i-increment]=5 r[i]=4<r[iincrement]=5,交换元素。在这里插入图片描述

  5. 同上继续循环至, i = 9 i=9 i=9 r [ i ] = 2 < r [ i − i n c r e m e n t ] = 9 r[i]=2<r[i-increment]=9 r[i]=2<r[iincrement]=9,交换元素。注意此时还要继续比较 r [ 5 ] r[5] r[5] r [ 1 ] r[1] r[1] r [ 5 ] < r [ 1 ] r[5]<r[1] r[5]<r[1]交换。在这里插入图片描述

  6. 第一轮 w h i l e while while后,序列如下所示。在这里插入图片描述

  7. 由于此时 i n c r e m e n t = 4 > 1 increment=4>1 increment=4>1,继续 d o do do循环。 i n c r e m e n t = i n c r e m e n t / 3 + 1 = 2 increment=increment/3+1=2 increment=increment/3+1=2,同上过程, i i i从3到9。当 i = 3 、 4 i=3、4 i=34时,不用交换,当 i = 5 i=5 i=5时,交换。在这里插入图片描述

  8. i = 6 、 7 、 8 、 9 i=6、7、8、9 i=6789时,不用交换。在这里插入图片描述

  9. 由于此时 i n c r e m e n t = 2 > 1 increment=2>1 increment=2>1,继续 d o do do循环。 i n c r e m e n t = i n c r e m e n t / 3 + 1 = 1 increment=increment/3+1=1 increment=increment/3+1=1,此时为最后一轮 w h i l e while while循环,同上过程。在这里插入图片描述

  10. 完成排序,结果如下图。在这里插入图片描述

性能分析

在上述排序过程中,增量" i n c r e m e n t increment increment"的选取十分关键,它选取什么最好目前还是一个数学难题,不过大量的研究表明,当增量序列为 d l t a [ k ] = 2 t − k + 1 dlta[k]=2^{t-k+1} dlta[k]=2tk+1时可以获得不错效果。总结其时间复杂度为 O ( n 3 / 2 ) O(n^{3/2}) O(n3/2),好于直接排序的 O ( n 2 ) O(n^{2}) O(n2),需要注意的是,增量序列的最后一个增量必须是1。而且希尔排序不是一个稳定的排序算法

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值