持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天
希尔排序
希尔排序是改良后的直接插入排序,又称“缩小增量排序”,由D.L.Shell于1959年提出而得名
思路
首先,我们将无序序列进行有间隔的分组,例如数组[2, 4, 1, 7, 6, 3, 9, 0],它的长度为6,一般间隔gap取其一半,小数舍去,我们就得到了gap = 4
有了间隔,我们就可以对其以gap距离进行分组:2和6一组,4和3一组,1和9一组,7和0一组,先对这四组进行组内排序,我们这里假设进行降序排序,组一就排序为[6, 2],组二为[4, 3],组三为[9, 1],组四为[7, 0],四个小组排序完成后,整个数组就更新成了:[6, 4, 9, 7, 2, 3, 1, 0],在宏观上已经变得有序,接下来gap/2,进行进一步细分
gap/2再舍去小数后,第二次的间隔就变为了2,也就是这样分组:第一组--[6, 9, 2, 1],第二组--[4, 7, 3, 0],再进行组内排序,结果依次为:[9, 6, 2, 1]、[7, 4, 3, 0],整体数组排序为了[9, 7, 6, 4, 2, 3, 1, 0],再将gap/2,继续进行如上排序,当增量减为一时,进行最后一次排序
希尔排序是基于插入排序在对几乎有序的数据进行排序时效率高的优点以及每次只能将数据移动一位的缺点做出的改进
性能方面:对含有近十万个元素的无序数组分别进行希尔排序与直接插入排序,分别计时,得到以下结果:
直接插入排序:test: 1:48.911 (m:ss.mmm)
希尔排序:test: 19.492s
实现(javascript):
//这里gap使用length/2
for(let gap = Math.floor(nums.length/2);gap > 0;gap = Math.floor(gap/2)){
for(let i = gap;i < nums.length;i++){
for(let j = i - gap;j >= 0;j-=gap){
if(nums[j] < nums[j + gap]){
Switch(nums, j + gap, j);
}
}
}
}
console.log('total', nums);
return nums[k-1];
时空复杂度及稳定性
空间复杂度为0(1)
希尔排序的时间复杂度很难分析,其平均复杂度介于O(n)与O(n^2)之间。希尔排序没有快速排序算法快,但比时间复杂度为O(n^2)的算法效率要好很多,因此在对中等规模数据排序时表现良好。
一次插入排序是稳定的,不会改变相同元素的相对顺序,但在希尔排序中,相同元素可能在各自分组的排序中移动,最后会被打乱,所以其为不稳定排序