【数据结构】希尔排序

大家好,我是苏貝,本篇博客带大家了解希尔排序,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️


目录

  • 一. 基本思想
  • 二. 实现希尔排序(以数组升序举例)
    • 2.1 预排序
    • 2.2 排序
  • 三. 对比直接插入排序和冒泡排序

一. 基本思想

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数gap,把待排序文件中所有记录分成gap个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,取gap=gap/2或者gap=gap/3+1(原因下面会说),重复上述分组和排序的工作。当到达gap=1时,所有记录已经排好序。


二. 实现希尔排序(以数组升序举例)

希尔排序可以分为2步:预排序和排序

预排序的目的是让数组接近有序

排序的目的是让数组有序

2.1 预排序

为了方便理解,我们先将gap置为3,即将数组分为3组。再将每一组都分别进行直接插入排序,最后数组就会接近有序
点击了解直接插入排序

下面代码中,第二个for循环就是每一组的直接插入排序,加入第一个for循环就是gap组的直接插入排序。因为相同组相邻的下标相差gap,所以将直接插入排序中的1全部替换成为gap。

c 复制代码
for (int i = 0; i < gap; i++)
	{
		for (int j = i; j < n - gap; j += gap)
		{
			int end = j;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
					break;
			}
			a[end + gap] = tmp;
		}
	}

上面代码也可以简写为下面这种形式,它的意思是多组并排,上面代码则是对每个组分别排序

c 复制代码
	for (int j = 0; j < n - gap; j++)
		{
			int end = j;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
					break;
			}
			a[end + gap] = tmp;
		}

2.2 排序

排序的目的是让数组从接近有序到有序。先让gap=n(数组大小)。当gap== 1时,就是对整个数组进行直接插入排序,直接插入排序后数组就有序。那如何让gap最后==1呢?我们可以将gap不断等于gap/2,这样不管n是奇数还是偶数,最后一定会等于1;也有人觉得不断将gap=gap/3+1更好,这样不管n是何值,最后也一定会等于1。

c 复制代码
void ShellSort(int* a, int n)
{
	//1.预排序
	//2.排序
	int gap = n;
	//gap>1是预排序,gap==1是直接插入排序
	while (gap > 1)
	{
		gap = gap / 3 + 1;

		for (int j = 0; j < n - gap; j++)
		{
			int end = j;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
					break;
			}
			a[end + gap] = tmp;
		}
	}
}

希尔排序的特性总结:

1.希尔排序是对直接插入排序的优化。

2.当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

3.希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定

4.稳定性:不稳定


三. 对比直接插入排序和冒泡排序

在这里我们用一个函数来测试三个排序的性能。让三种排序都排列同样的100000个随机数字,比较3个排序的时间。rand函数用来生成随机值,clock函数用来返回程序运行的时间。因为排序用的时间可能比较长,所以在这里我们将Debug换成Release

c 复制代码
void TestOP()
{
	srand(time(0));
	const int N = 100000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	int* a2 = (int*)malloc(sizeof(int) * N);
	int* a3 = (int*)malloc(sizeof(int) * N);

	for (int i = 0; i < N; ++i)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
	}

	int begin1 = clock();
	InsertSort(a1, N);
	int end1 = clock();

	int begin2 = clock();
	ShellSort(a2, N);
	int end2 = clock();

	int begin3 = clock();
	BubbleSort(a3, N);
	int end3 = clock();

	printf("InsertSort:%d\n", end1 - begin1);
	printf("ShellSort:%d\n", end2 - begin2);
	printf("BubbleSort:%d\n", end3 - begin3);

	free(a1);
	free(a2);
	free(a3);
}

结果如下,我们发现希尔排序比直接插入排序要快速的多


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

相关推荐
vvilkim33 分钟前
数据结构类型、区别与应用场景:一篇讲透选型逻辑
数据结构
lisw055 小时前
Dayhoff的PAM替换矩阵理论评介!
线性代数·算法·矩阵
阿卡好可爱5 小时前
Lua 热更新不生效:改完文件线上仍是旧逻辑,package.loaded 与 upvalue 重绑定详解
数据结构·分布式·后端·架构·lua
一起学安全技术5 小时前
拆大模型 03|注意力的一句话版本:不用论文讲清 Attention
深度学习·算法·语言模型·transformer
Delightrs6 小时前
Rust LeetCode238 算法题解
开发语言·算法·rust
自信150413057597 小时前
重生之从0开始学习c++之——vector-中篇
c++·学习·算法
GoAI18 小时前
DeepSeek Harness Memory (一)主流记忆插件总结
后端·算法·面试
Pniubi18 小时前
力扣54.螺旋矩阵
算法·leetcode·矩阵
choumou_M21 小时前
算法_1:由浅入深学习快速排序QuickSort
学习·算法·排序算法