前言
经历上周元旦三天假期,这周又是双休,元气终于恢复了,如果不打游戏可能更好,索性又又又一次把游戏卸载了,工作以后想放松一下,发现打游戏并不是一个好的选择,打游戏反而让我更加的劳累了,刷刷视频又有负罪感,而且刷视频时间过得太快了,一个空间微视,一个B站,我最常用的两个刷一下就一天没了,还是控制不住,虽然B站也是用来学习的,经不住首页推荐呀,自己自制力太差了,有空还是多看看掘金和CSDN吧,至少看看文章会有收获。这周继续更一篇排序算法吧。
一、什么是希尔排序?
1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。我个人的理解而言,觉得希尔排序是通过不断的分组排序,从一开始的两个组别不断的二分下去成为多个小组,最后分组为1的时候也就是最后一次排序(此时已是插入排序,但是数组有序所以速度会快很多)。插入排序按照特定方法(步长为1)去执行,希尔排序调整了步长,分组跨越式的排序,从而做到比插入排序更加快一点,简而言之,插入排序是步长为1的希尔排序,希尔排序是插入排序的改进,所以学习希尔排序之前要先了解插入排序。
二、算法描述
算法步骤:
- 选择一个增量序列grap1,grap2,…,grapk,其中grapi>grapj,grapk=1;(所谓序列,就是每次分组的长度,在我的demo里面使用二分法作为增量序列)
- 按增量序列个数k,对序列进行k 趟排序;
- 每趟排序,根据对应的增量grapi,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
算法复杂度:
- 时间复杂度:
- 最好:O(n) 如果序列是已经排好的序列,则一次循环即可。
- 最坏:O(n2)
- 平均: O(n3/2)
- 空间复杂度:O(1)
- 稳定性:不稳定
三、JS代码实现
老规矩,懂前端的同学打开控制台(浏览器按F12键,现在好像都是f12吧)复制下面代码粘贴到控制台回车就可以运行看到结果了。(๑′ᴗ‵๑)。
代码如下(示例):
function shellSort(ary) {
var len = ary.length;
for (var grap = Math.floor(len / 2); grap > 0; grap = Math.floor(grap / 2)) {
for (var i = grap; i < len; i++) {
var j = i;
var cur = ary[i];
while (j - grap >= 0 && cur < ary[j - grap]) {
ary[j] = ary[j - grap];
j -= grap;
}
ary[j] = cur;
}
}
return ary;
}
let ary = [9, 8, 7, 1, 2, 3, 6, 5, 4, 0];
console.log(shellSort(ary));
运行结果图:
总结
希尔排序感觉需要自己去阅读代码,结合别人的解释才能理解算法中的思想,我刚开始看代码也是没转过弯了,这里希尔排序中分组是同时进行的,在算法中是每个小组的排序,一组组的和之前的排序比较,所以单看代码理解起来可能有点绕。我个人理解而言就是,先将序列划分成若干个小组分别排序,从局部有序逐渐的转变为全局有序。
——2021-1-10 22:45 晚安了,打工人。
今日份励志名言:
业精于勤,荒于嬉;行成于思,毁于随。
——韩愈·《进学解》