【排序】希尔排序(C语言实现)



前言


本章将详细介绍希尔排序的思想及实现,由于希尔排序是在插入排序的思想上进行升华,所以如果不知道插入排序或者不熟悉的可以先看看这篇文章:《简单排序》中的直接插入排序。


1. 希尔排序的思想

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成gap个组,所有距离为gap的数据分在同一组内,并对每一组内的记录进行排序。当gap组都排完以后,我们将gap缩小,重复上述分组和排序的工作。当gap = 1时(此时就是直接插入排序),所有记录在统一组内排好序。

在这里插入图片描述

具体步骤如下图:

在这里插入图片描述
在这里插入图片描述
请添加图片描述

我们可以按照上面的思路,来用代码进行模拟实现:

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 0)
	{
		// 每次gap/2,直到最后gap会等于0
		gap /= 2;
		int count = 0;
		// 调整几组取决于gap为多大
		while (count < gap)
		{
			// 每组调整的步骤
			for (int i = 0;i < n - gap;i += gap)
			{
				int tmp = a[i + gap]; // 定义一个临时值,用来保存每次要插入的数
				int j = 0; //控制循环的变量
				for (j = i;j >= 0;j -= gap)
				{
					// 从后面开始比,如果tmp比后面的数小,就将后面的数往后移gap
					if (a[j] > tmp)
						a[j + gap] = a[j];
					else// 如果tmp比后面的数要大,就直接退出,因为我们是从第一个数开始这样操作的,前面能够保证是有序的
						break;
				}
				a[j + gap] = tmp;
			}

			count++;
		}
	}
}

希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定:
    《数据结构(C语言版)》— 严蔚敏在这里插入图片描述
    《数据结构-用面相对象方法与C++描述》— 殷人昆
    在这里插入图片描述
  4. 稳定性:不稳定


2. 希尔排序的一些小优化

我们上面那个实现的方式是取gap=[n / 2],gap=[gap / 2],直到gap=1,但我们看到 《数据结构-用面相对象方法与C++描述》— 殷人昆 中提到Hnuth取gap的方法,可以有一定程度上的提高我们的速度,具体是怎么提高的呢,因为这块涉及到很难的数学知识,目前还没人能够给出完整的数学分析,所以我们也不必去纠结,只要记住他们这些大佬经过多次实验提出的结论就可以了。

这里我打算进行两个优化:

  1. 就是gap的取值
  2. 我们上面每次排序是一组一组的排序,其实我们可以一次性全部排序完(这里效率上没有提升,只是代码量减少了)

具体代码如下:

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1) // gap最小等于1,所以这里的循环条件需要控制一下
	{
		// 每次gap/3 + 1,+1的目的是为了保证gap一定会等于1
		gap = gap / 3 + 1;
		// 我们将gap组一起调整
		for (int i = 0;i < n - gap;++i)
		{
			int tmp = a[i + gap];// 定义一个临时值,用来保存每次要插入的数
			int j = 0; // 控制循环的变量
			for (j = i;j >= 0;j -= gap)
			{
				if (a[j] > tmp)
				{
					a[j + gap] = a[j];
				}
				else
					break;
			}
			a[j + gap] = tmp;
		}
	}
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hyt的笔记本

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

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

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

打赏作者

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

抵扣说明:

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

余额充值