排序算法4----希尔排序(C语言)

       ef4c08a6feec4efc85e7b0a0b0711ba2.png

        经过大量测试,希尔排序的平均时间复杂度:O(N*1.3),或者O(NlogN),这就非常牛逼了,发明这个算法的作者简直是个天才!最优时间复杂度:O(N),即已经有序。

        希尔排序和插入排序类似,都是将前面的区间看作有序,然后比较插入。其实准确的说,插入排序是希尔排序的一种特例(gap == 1)。

        先给大家来一个动态图,理解理解。

db3781b0803e4bb098bad2be4ad2f470.gif

        下边放几个抽象图,大家仔细理解一下,gap的作用就在下面体现出来。

        fa84e5016e3c42cc81f1654cdc895e0f.png

708020321d7c4a0b949061aa37c3476b.png

6f9d71acf5ec4706be490945693d415c.png

        希尔排序只是将gap作为一个变化量,逐渐向1逼近,每次gap的值都来执行一遍插入排序。

上代码:

void ShellSort_incline(int* arr, int n)
{
	//确定初识gap,将gap初始化到最大n,以便于后面gap能从最大缩小到最小
	int gap = n;

	while (gap > 1)
	{
		//gap逐渐缩小
		//gap/3 +1是为了确保最后gap能达到1
		//也可以gap = gap / 2,gap怎么变都可以
		gap = gap / 3 + 1;
		
		//i从0 --> n-gap-1,每次比较相距gap的两个数
		for (int i = 0; i < n - gap; i++)
		{
			//下面就是和插入排序一样的,只不过比较的是相距为gap的位置
			//其实插排就是希尔排序的特殊情况,即gap = 1
			int end = i;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

         那么就会有人问了:既然gap最终都会等于1,等于1的时候那不就是插入排序了吗,为啥要多此一举呢,时间复杂度不会更高吗?

        答案是有必要:因为从代码上来看,当前一个数比后一个数小的时候,便直接break结束循环。那么gap从大到小执行比较插入数据时,会将无序的数组,逐渐变得大致有序,并非完全有序。那么最后gap逐渐趋于一的时候,因为数组已经大致有序,变有很大可能会直接执行break,不会反复循环,而由于gap比较大的时候,两个需要比较数之间又间隔很大,那么每次比较插入就不会执行n次,而是会执行一个取决于gap的大小的次数。

        即总的来说:gap很大时,每一趟执行的次数少,而当gap很小时,有很可能会直接执行break,执行的次数也很小。综合来说,实质上,希尔排序是对插入排序的一种优化。

        点个赞再走!!!不然不发了!!!

        3bf36354cffe4b8fb3287a7a7ead243c.png

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夹心宝贝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值