排序2:希尔排序(缩小增量排序)

上一期,我们介绍了直接插入排序

这一期,我们来介绍希尔排序的底层逻辑和代码实现。


目录

希尔排序的基本思想

单趟的实现

整个排序的实现

总结


希尔排序的基本思想

先选定一个整数gap,把待排序文件中所有记录分成gap个 组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后取重复上述分组和排序的工 作。当到达gap =1 时,所有记录在统一组内排好序
光看概念十分抽象,我们看下面的图:

当gap = 3时,我们可以把一组数据分为3组,每一组中,单独进行排序。通过这样,我们可以让数据大致趋向于有序。这就是单趟的底层原理了。
分组排序后的结果:

 然后,逐渐缩小gap进行排序,数据就会越来越有序。

  

单趟的实现

从单趟实现起,逻辑可以分为下面几步:
        1、选定gap然后分组。
        2、每一组从后往前遍历排序。
        3、与后面一个间隔为gap的数比较。
        4、a:如果后面的数要小于前面的数,那么小的数插入到前面,然后被插入位置的后面的数字各往后移动gap格。
代码如下:
int gap = 3;
for (int i = 0; i < n - gap; i += gap)
		{
			int end = i;
			int temp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > temp)
				{
					a[end + gap] = a[end];
					a[end] = temp;
					end -= gap;
				}
				else
				{
					break;
				}
			}
		}

不难看出,这和直接插入排序的单趟是很相似的。

整个排序的实现

核心思想: 

        1、gap递减,缩小排序组数,最终到gap = 1的时候,就是一次直接插入排序了。

        2、齐头并进。

       

代码如下:

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//间隔逐渐缩小,最后一次等于插入排序
		gap = gap / 3 + 1;
		//齐头并进
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int temp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > temp)
				{
					a[end + gap] = a[end];
					a[end] = temp;
					end -= gap;
				}
				else
				{
					break;
				}
			}
		}
	}
}

i 的每次增加从gap变成了1,这样的目的是为了能够逐一的往后走下去,使得每组都能照顾到。

gap赋值n,每次除以3。除以3后加上1的目的是为了能够最后数字变成1。

我们来测试一下:

 结果:

 

总结

关与希尔排序的时间复杂度问题,是很难计算出来的。

殷人昆老师的《数据结构-用面相对象方法与C++描述》一书中提到:

在n在某个范围的内的时候,时间复杂度约为n^1.3 。当数据过多的时候,时间复杂度也会提高到

n(logn)²。

而希尔排序在排序中也是不稳定的(不稳定:即有可能因为某部分的有序破坏原先的已经变为有序的部分)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

青衫哥

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

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

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

打赏作者

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

抵扣说明:

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

余额充值