排序——希尔排序

希尔排序

希尔排序步骤

希尔排序的核心还是插入排序 ,但是把插入排序分成两部分,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;
		}
	}
}
相关推荐
int型码农2 小时前
数据结构第八章(一) 插入排序
c语言·数据结构·算法·排序算法·希尔排序
UFIT2 小时前
NoSQL之redis哨兵
java·前端·算法
喜欢吃燃面2 小时前
C++刷题:日期模拟(1)
c++·学习·算法
SHERlocked932 小时前
CPP 从 0 到 1 完成一个支持 future/promise 的 Windows 异步串口通信库
c++·算法·promise
怀旧,2 小时前
【数据结构】6. 时间与空间复杂度
java·数据结构·算法
积极向上的向日葵2 小时前
有效的括号题解
数据结构·算法·
GIS小天2 小时前
AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月7日第101弹
人工智能·算法·机器学习·彩票
_Itachi__3 小时前
LeetCode 热题 100 74. 搜索二维矩阵
算法·leetcode·矩阵
不忘不弃3 小时前
计算矩阵A和B的乘积
线性代数·算法·矩阵
不爱写代码的玉子3 小时前
HALCON透视矩阵
人工智能·深度学习·线性代数·算法·计算机视觉·矩阵·c#