系列文章目录
【每天学一点 - 算法篇 - 排序 - 插入排序】
前言
小时候听蛋炒饭
嘿,蛋炒饭,最简单也最困难 ----《蛋炒饭》
长大学希尔排序
希尔排序是算法非常简单且又极其复杂的分析的一个好例子 ----《数据结构与算法分析》
一、什么是希尔排序
希尔排序是最常用的叫法,但其实光说希尔排序确实不太容易记住它到底是怎么排序的, 毕竟希尔只是个人名,这个时候就要祭出它的学名 – 缩减增量排序 那缩减增量又是怎么排序的呢, 先进一段前情提要 【每天学一点 - 算法篇 - 排序 - 插入排序】 昨天刚写完插入排序,而增量缩减排序就是插入排序plus
二、原理
1.思路
那么这个插入排序plus又是怎么提升性能的呢? 因为插入排序是连续比较的,较差情况下每一个数都要跟前面所有的数比较一遍,那这时候希尔就想,我要是先间隔着比较,相当于我先做预排序,然后再进行插入排序会不会快一点呢 就是假设一个比较大的增量,相隔增量长度的数先进行一次插入排序, 然后逐步缩小这个增量,再次进行插入排序, 直到增量变成1的时候,进行玩插入排序, 最后的结果那就一定是有序队列了 这就是所谓的缩减增量排序
2.示例
3.抽象
要理解这个插入排序plus,要找到一点“分而治之”的感觉(实际并没有用到分治) 就是把整体先分好多组,让每个组都单独成为有序队列, 然后逐步减少分组数量,最后是整体成为有序队列
三、代码
实现方法
public int[] shellSort(int[] a) {
for (int gap = a.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < a.length; i++) {
int check = a[i];
int j;
for (j = i; j >= gap && check < a[j - gap]; j -= gap) {
a[j] = a[j - gap];
}
a[j] = check;
}
}
return a;
}
测试方法
@Test
public void shellSort() {
int[] a = new int[]{3, 9, 5, 4, 8, 7, 1, 6, 2};
System.out.println(Arrays.toString(new Sort().shellSort(a)));
}
四、复杂度
这时候就到了 又极其复杂的分析 的部分了 首先说,仅从上面的操作上看,好像希尔排序跟插入排序也不是很看得出来谁的优势更大,谁能更快,毕竟你后面排序快的前提是进行了预排序,较差场景下还是每个数都跟其他的数分别比对了一遍。 那这个时候就要提到之前一直没有具体讲的增量缩减排序中的增量了, 诚然,如果只是单纯的二分取增量,时间复杂度跟插入排序不相上下, 但是老黑(hibbard,名字确实不好记,就叫老黑吧)提出了一个观点 如果增量缩减过程中,有三次的增量程线性关系,那就可以省出一次增量过程 比如三次的增量分别是3,5,13, 这时候3+2*5=13,那么13这次其实是可以省下来的,因为只用3和5排序就可以保证 第一个数<第四个数<第九个数<小于第十四个数,也就不需要13的那次排序了, 所以这个增量序列要没有公因子才行,老黑就提出了下面这个序列 1,3,7,,,,,2k-1 经证得时间复杂度为O(N3/2),证明过程等我学明白了再回来填坑 时光荏苒,岁月如梭,转眼就到了2022年,经过不断的实验与测试,人们又发现了一个效率更高的序列
{1,5,19,41,109,…},该序列中的项或者是94i-92i+1的形式,或者是4i-3*2i+1的形式。
这个序列也只是使用中发现效率更高,并不能实际证明出具体复杂度 现在也没有人证明出了希尔排序中效率最高的增量缩减序列 只能说希尔排序真不愧是 又极其复杂的分析 的排序算法
总结
并没能证明出希尔排序的复杂度,给自己埋个坑吧,争取尽快回来填上
|