排序算法-插入排序-希尔排序

397 阅读3分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

希尔排序

介绍

希尔排序 这是十大排序算法里的基础排序,这个理解起来比 直接插入排序算法 有点难。

又称 缩小增量排序。它属于插入排序里面的,它比直接插入排序算法更优,是直接插入排序算法的改进版。是一种 非稳定 排序算法,不能用于链表。

为什么又称为 缩小增量排序,是因为它会优先比较距离较远的元素,然后依次缩减 间隔序列(增量),再进行插入排序。直到 间隔序列(增量) 为1时,进行最后一次直接插入排序,排序结束。

问题

我这里刚开始遇到希尔排序时,遇到的问题有两个

  • 增量:希尔排序算法的关键 间隔序列的设定(增量)。它是是提前指定好?还是说动态的定义间隔序列?

  • 奇偶数:网上大多数原数据的个数都是 偶数,来进行排序讲解的例子。但是如果原数据的个数是奇数的话,最后一个单的是如何处理的呢?处理方案是什么呢?

解决

  • 首先我们先处理 间隔序列(增量)的问题

    这里大部分的选择都是,(数据总长度 / 2) 然后,向下取整,得到的结果 继续/2,向下取整,直到间隔序列(增量)为1。

    用代码表示就是

      // increment 间隔序列(增量)值
      for (let increment = Math.floor(len / 2); increment > 0; increment = Math.floor(gap / 2)) {}
    
  • 奇偶数 问题

    通过对期画图演示,了解下来,奇偶数问题,其实是没有影响的,可以查看下面演示,即可知道为什么奇偶数没有影响。

演示

注意以下相同背景颜色为一组

  1. 初始化

    原始数组 [10, 7, 6, 3, 0, 1, 4, 2, 5, 9, 8],总长度 len = 11,为奇数。

image.png

  1. 第一次增量

    第一次的增量 Math.floor(len / 2) = 5,数组分 6 组, 为 [10,1],[7,4],[6,2],[3,5],[0,9][10,8]

    这里可能会有人对最后一组有疑问,为什么是 [10,8],而不是 [1,8]。因为我们是循环遍历依次执行,所以到最后一组的时候, 1 所在的位置的值已经变成了 10

image.png

  1. 第一次的排序结果:[1, 4, 2, 3, 0, 8, 7, 6, 5, 9, 10]

  2. 第二次增量

    第二次的增量 Math.floor(5 / 2) = 2,数组分 2 组, 为 [1,2,0,7,5,10],[4,3,8,6,9]

image.png

  1. 第二次的排序结果:[0, 3, 1, 4, 2, 6, 5, 8, 7, 9, 10]

image.png

  1. 第三次的增量 Math.floor(2 / 2) = 1,最终的排序结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

题目

  1. 排序数组-912

    给你一个整数数组 nums,请你将该数组升序排列

代码

  • 排序数组 912题
        // shellSort
        const sortArray = (nums) => {
            const numsLength = nums.length // 10
            for (let increment = Math.floor(numsLength / 2); increment > 0; increment = Math.floor(increment / 2)) {
                // 我们从第 increment 个开始,依次往后
                for (let i = increment; i < numsLength; i++) {
                    const current = nums[i]
                    let j = i
    
                    // 与间隔为 increment 的值 进行比对,也就是开始插入排序
                    while (j - increment >= 0 && current < nums[j - increment]) {
                        nums[j] = nums[j - increment]
                        j = j - increment
                    }
    
                    nums[j] = current
                }
            }
            return nums
        }
    

总结

希尔排序算法直接插入排序算法 效率高的原因是:当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,直接插入排序对于有序的序列效率很高。

注意:由于 希尔排序算法不稳定性,所以 不能 用于 链表(因为链表不能随机访问)。