十大经典排序算法 ( 四 ) 希尔排序
介绍 :
希尔排序(Shell's Sort)是插入排序的一种又称 “ 缩小增量排序 ”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。
-
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
-
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
算法原理 :
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
动图演示 :
算法稳定性 :
由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
时间复杂度 :
希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比 o( n^2 ) 好一些。
希尔排序的复杂度和增量序列是相关的
{1,2,4,8,...}这种序列并不是很好的增量序列,使用这个增量序列的时间复杂度(最坏情形)是O(n^2)
Hibbard提出了另一个增量序列{1,3,7,...,2^k-1},这种序列的时间复杂度(最坏情形)为O(n^1.5)
Sedgewick提出了几种增量序列,其最坏情形运行时间为O(n^1.3),其中最好的一个序列是{1,5,19,41,109,...}
应用场景 :
专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法。因为对于中等大小的数组它的运行时间是可以接受的。 它的代码量很小,且不需要使用额外的内存空间。虽然有更加高效的算法,但 除了对于很大的 N,它们可能只会比希尔排序快两倍(可能还达不到),而且更复杂。如果你需要 解决一个排序问题而又没有系统排序函数可用(例如直接接触硬件或是运行于嵌入式系统中的代 码),可以先用希尔排序,然后再考虑是否值得将它替换为更加复杂的排序算法。
Java代码 :
/** * 希尔排序 : 把数组按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的元素越来越多,当增量减至 1 时,整个数组恰被分成一组,算法便终止。 */ public class ShellSort { public static void sort(int[] arr) { // 判断边界条件 if (arr == null || arr.length < 2) { return; } int gap = 1;// 增量 while (gap < arr.length) { gap = gap * 5 + 1;// 增量序列 : 1 , 4 , 13 , 40 , 121 , 364 , 1093... } // 进行分组 while (gap > 0) { // 对各个分组进行 插入排序 for (int i = gap; i < arr.length; i++) { insertValue (arr, gap, i);// 将arr[i]插入到所在分组的正确位置上 } gap = gap / 5;// gap收缩,直至1 } } /** * 将arr[i]插入到所在分组的正确位置上 ( 代码与插入排序几乎一致 ) * * @param arr 数组 * @param gap 增量 * @param i 数组下标 */ private static void insertValue(int[] arr, int gap, int i) { int tmp = arr[i]; int j = i - gap; // 按组进行插入(组内元素两两相隔gap) while (j >= 0 && arr[j] > tmp) { arr[j + gap] = arr[j]; j -= gap; if (j + gap != i) { arr[j + gap] = tmp; } } } }
如果还有没看懂的同学 , 可以看看下面这个有大量图解的博客
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端