排序——希尔排序

希尔排序

希尔排序步骤

希尔排序的核心还是插入排序 ,但是把插入排序分成两部分,1.预排序2.插入排序 。先对原数组进行预排序,使数组接近有序(让更大的数字和更小的数字更快的分配到两边),然后再对已经接近有序的数组进行插入排序,这样就会快很多。

时间复杂度约为:O(N^1.3);空间复杂度O(1); 由于希尔排序有分预排序,所以有可能对相同大小的数字会改变他们的相对位置,是不稳定排序

预排序:把原数组分组,然后对不同的分组进行插入排序,例如下面这串逆序的数字,我们对其分组分为3组,先进行预排序,让数组接近有序。

不断地进行预排序,直到我们取的gap=1(gap表示同组数据之间的间距),就是直接插入排序,这样我们就很好的优化了直接插入排序的时间复杂度,希尔排序就是直接插入排序的进阶版。

我们用gap表示一组的间隔,这样总共就有gap组(上述案例gap=3)。当gap过大时,较大的大的数和较小的数就能更快地跳到两边,但是相对的,一次gap排完后数组也更不接近有序;当gap过小时,就约等于直接插入排序,遇到数据过多时,希尔排序就失去了原本的意义。所以一般先给gap赋值n(总数)再取gap=gap/2或者gap=gap/3+1(gap除2的最后一次gap一定是1,gap除3的最后一次可能会是0,为了让最后一次gap一定为1,所以再+1),这样就刚好达到了一个平衡。(gap=1就是直接插入排序)

****总结:****希尔排序核心还是是直接插入排序,差别在于直接插入排序就是gap=1,而希尔排序是gap从n/2或者n/3+1开始不断地趋于1,最终gap=1进行一次直接插入排序就完成了。但希尔排序内部还有不同写法,下述为希尔排序的两种写法。

希尔排序写法

单组排序:

排完一组再重新返回起点,再后移一位排下一组,总共排gap组。

多组并排:

每次排序完后往后移动一位,排下一组,当向后移gap位后又重新排第一组。即i=0时是一组,i++后又是一组,间隔是gap,(i=0和i+=gap是同一组)

计算希尔排序时间复杂度

我们先假设n(总数)很大,外面的时间复杂度就为log3n,接着计算内部预排序的时间复杂度。由于n很大,那么第一次gap=n/3+1也会很大,我们忽略后面的+1,这样相当于有n/3组,每组有3个元素,当逆序情况时,每组要移动1+2=3次,那么累计的次数就是n/3*3=n。

然后gap在除3,gap=gap/3+1,我们在忽略+1,就得到了gap=n/9,相当于分成了n/9组,每组要移动(1+2+3+...+8)=36次,再当当前数据还是逆序,那么累计次数为n/9*36=4n,看起来是变大了的,但实际上因为我们移动过了原逆序数据,第二次移动时肯定不为完全逆序,次数肯定会减少。

这样一直减小gap,知道gap=1时,就是直接插入排序,这时由于我们的数据经过上述预排序后已经变得非常接近有序了,所以累计次数就相当于n(走一遍数组,调一小部分),总时间复杂度就为上述累计次数相加,时间复杂度大约为O(N^1.3)

希尔排序代码

单组排序:

cpp 复制代码
//希尔排序
void ShellSort(int *arr, int n)
{
	int gap = n;
	//重新上来时gap=1就说明上次排序是直接插入排序
	while (gap > 1)
	{
		//gao有两种取法:如下
		//gap = gap / 2;
		gap = gap / 3 + 1;

        //单组排序
		//一组一组排序,排完一组再排下一组,总共排gap组
		for (int j = 0; j < gap; j++)
		{
			//每组下标i+=gap,向后移gap位
			for (int i = 0; i < n - gap; i += gap)
			{
				//直接插入
				int end = i;
				int tmp = arr[end + gap];
				while (end >= 0)
				{
					if (tmp < arr[end])
					{
						arr[end + gap] = arr[end];
						end -= gap;
					}
					else
						break;
				}
				arr[end + gap] = tmp;
			}
		}
	}
}

多组并排:

cpp 复制代码
//希尔排序
void ShellSort(int *arr, int n)
{
	int gap = n;
	//重新上来时gap=1就说明上次排序是直接插入排序
	while (gap > 1)
	{
		//gao有两种取法:如下
		//gap = gap / 2;
		gap = gap / 3 + 1;

		//多组并排,i=0时是一组,i++后又是一组,间隔是gap,(i=0和i+=gap是同一组)
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (tmp < arr[end])
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
					break;
			}
			arr[end + gap] = tmp;
		}
	}
}
相关推荐
gwf2169 小时前
磨损均衡算法(Wear Leveling)——SSD如何让每块闪存“公平退休“?
运维·数据库·人工智能·python·嵌入式硬件·算法·智能硬件
noipp9 小时前
推荐题目:洛谷 P6231 [JSOI2013] 公交系统
c语言·数据结构·c++·算法·游戏·洛谷·luogu
c238569 小时前
C/C++每日一练6
c语言·c++·算法
AI小码10 小时前
把动作「画」给视频世界模型,跨本体双向推演,李飞飞参与
大数据·人工智能·算法·ai·大模型·音视频·编程
KaMeidebaby11 小时前
卡梅德生物技术快报|bli亲和力检测gst:告别批量跑胶:BLI实时酶切监测技术加速GST融合蛋白下游流程优化
前端·网络·数据库·人工智能·算法
alphaTao11 小时前
LeetCode 每日一题 2026/7/20-2026/7/26
算法·leetcode
青山木15 小时前
Hot 100 ---腐烂的橘子
java·数据结构·后端·算法·leetcode·广度优先
未来之窗软件服务15 小时前
计算机考试-快速排序—东方仙盟
数据结构·算法·排序算法·仙盟创梦ide·东方仙盟
小龙报15 小时前
【优选算法】1. 水果成蓝 2.找到字符串中所有字母的异位词
java·c语言·数据结构·数据库·c++·redis·算法
wWYy.15 小时前
数据结构:跳表
数据结构