希尔排序:一个“跳房子游戏”
欢迎来到我的:世界
希望作者的文章对你有所帮助,有不足的地方还请指正,大家一起学习交流 !
目录
- 前言
- 内容
- 排序的概念与分析
- 动图实现
- 代码实现
- 总结
前言
希尔排序(Shell Sort)是一种基于插入排序的算法,由Donald Shell于1959年提出。它克服了插入排序在大规模数据集上的效率问题,通过引入一个“增量”(gap)的概念来改进排序过程。
内容
核心思想:
希尔排序的基本思想是将待排序的记录序列分割成若干子序列,每个子序列由相隔某个“增量”的记录组成,然后对每个子序列进行直接插入排序。随着增量逐渐减小,子序列逐渐合并,直到整个序列有序.
排序的概念与分析
想象一下,你在跳房子游戏,每次跳的步长都不一样。这就是希尔排序的精髓——它是一种“跳跃”排序算法。由D.L.希尔在1959年提出,希尔排序继承了插入排序的“温柔”,但又加入了自己的“跳跃”特性。
-
步骤一:选择一个“跳跃”距离
希尔排序的第一步是选择一个“跳跃”距离,这个距离不是固定的,而是随着时间的推移逐渐减小。就像你在跳房子游戏中,开始时可以跳一大步,但随着游戏的进行,步长越来越小。 -
步骤二:分组“跳跃”
接下来,我们将数组分成若干组,每组的元素间隔就是那个“跳跃”距离。比如,如果跳跃距离是4,那么第一组就是第1、5、9…个元素,第二组就是第2、6、10…个元素,以此类推。 -
步骤三:组内“插入排序”
在每个组内,我们执行插入排序。就像你在整理书架上的书,一本一本地比较,然后插入到正确的位置。这个过程在每个组内独立进行。 -
步骤四:缩小“跳跃”距离
当我们完成一轮组内排序后,我们缩小跳跃距离,通常是减半。然后,我们重复步骤二和步骤三,直到跳跃距离变为1。这时候,整个数组就只有一个组了,我们再次执行插入排序,整个数组就变得井然有序。
注意
希尔排序之所以要“跳”,是因为它试图减少比较和移动的次数。通过分组和逐渐减小跳跃距离,希尔排序可以在一定程度上打破原始数据的无序性,使得最后的插入排序更加高效。
虽然希尔排序比普通的插入排序要快,但它的最坏情况时间复杂度仍然是O(n^2)。不过,当跳跃距离选择得当时,它的平均性能可以接近于
O(n ^ 1.3)
。
动图实现
代码实现
// ShellSort函数用于对整数数组进行希尔排序
// 参数:
// a:指向待排序整数数组的指针
// n:数组中元素的个数
void ShellSort(int* a, int n)
{
// 初始化间隔gap为数组的长度n
int gap = n;
// 当间隔gap大于1时,进行分组排序操作
while (gap > 1)
{
// 更新间隔gap的值,采用gap = gap / 3 + 1的方式
// 这种方式可以让间隔逐渐变小,最终会变为1
gap = gap / 3 + 1;
// 对每个间隔gap下的子序列进行插入排序操作
for (int i = 0; i < n - gap; i++)
{
// 记录当前要比较和移动的子序列中起始位置的前一个元素的索引
int end = i;
// 暂存当前要插入排序的元素值,即间隔为gap的后续元素值
int tem = a[end + gap];
// 只要当前位置end的元素大于暂存的要插入的元素tem,并且end不小于0
// 就将较大的元素往后移,为要插入的元素腾出合适的位置
while (a[end] > tem && end >= 0)
{
// 将较大的元素a[end]移动到间隔为gap的后续位置a[end + gap]
a[end + gap] = a[end];
// 更新end的值,使其向前移动gap个位置,继续向前比较
end -= gap;
}
// 当找到合适的位置后,将暂存的元素tem插入到该位置a[end + gap]
a[end + gap] = tem;
}
}
}
注意:希尔排序不相邻的元素也会进行位置交换,因此是 不稳定的排序算法
总结
最后,如果你对希尔排序感兴趣,不妨亲自尝试一下。
就像不是所有的跳跃都能到达终点一样,希尔排序也不是万能的。它在某些情况下可能不如快速排序或归并排序高效。但是,了解不同的排序算法,就像是了解不同的舞蹈步伐,有时候,选择合适的步伐,才能跳出最优雅的舞蹈。
希望你们喜欢这篇关于希尔排序的“跳跃”之旅。下次当你看到一堆乱糟糟的数据时,不妨试试希尔排序,让它带你“跳”到有序的新世界!🚀🚀🚀
到了最后:感谢支持
------------对过程全力以赴,对结果淡然处之