小白也能看懂的-希尔排序

希尔排序是对插入排序的一种改进

本质是:

  1. 将数组按照 h 的跨度进行分割
  2. 分割后将跨度为 h 的数组值进行交换
  3. 然后向前移动跨度为 h 的距离,再交换跨度为 h 距离值
  4. 缩小跨度,对跨度内的数据进行插入排序操作

简单说分两步:

  1. 让数据值大的尽量往后排,减少和前面数据的位置交换次数(减少了内存的操作)
  2. 缩小 跨度 h 用插入排序进行 h 跨度内的排序

接下来以数组 nums = [6, 5 , 4, 3, 2, 1] 举例说明希尔排序的具体过程,nums 按照倒序排列是为了可以让大家简单,清晰的理解按照跨度进行数据交换,完整算法如下:

 public static int[] shell(int[] nums) {
        int n = nums.length;
        int h = 1;
        // 计算跨度 h
        while (h < n / 3) {
            h = 3 * h + 1;
        }
        while (h >= 1) {
            // 尽量让大的数值往后排
            for (int i = h; i < n; i++) {
                // 对 h 跨度内的数据进行插入排序操作
                for (int j = i; j >= h; j -= h) {
                    if (nums[j] < nums[j - h]) {
                        int temp = nums[j];
                        nums[j] = nums[j - h];
                        nums[j - h] = temp;
                    }
                }
            }
            // 缩小跨度
            h = h / 3;
        }
        return nums;
 }

1、首先将数组按照 h = 3 * h + 1 计算得到跨度 h = 4;

while (h < n / 3) {
   h = 3 * h + 1;
}

这里可以理解为,设置了一个跨度因子数为 3,根据数据规模n 的大小,可以动态的调整跨度区间,n 越大 跨度 h 越大,为了尽可能减少交换的次数。

2、进入第一次while 循环

  • nums = [6, 5 , 4, 3, 2, 1]
  • 外层循环初始条件为:i = h = 4, n = 6
  • 内层第一次循环:循环初始条件为:j = i = 4, h = 4, j >= h,比较 nums[ j = 4] = 2,nums[ j - h = 0] = 6,2 < 6 交换位置,6和2之间的跨度为4
    此时 nums 如下:
    nums[0] = 2,nums[1] = 5,nums[2] = 4,nums[3] = 3,nums[4] = 6, nums[5] = 1
  • 内层循环结束后 j = j - h = 0; 退出内层循环

3、外层第二次循环初始条件为:i 的初始值为4,步骤2完成后进行 i++ 操作,i = 5

  • nums = [6, 5 , 4, 3, 2, 1]
  • 内层循环条件为:j = i = 5,h = 4,j >= h (5 >= 4),比较 nums[ j = 5 ] = 1, nums[ j - h = 1 ] = 5,1 < 5 交换位置,5和1 之间的跨度为4
    此时 nums 如下:
    nums[0] = 2nums[1] = 1,nums[2] = 4,nums[3] = 3,nums[4] = 6nums[5] = 5
  • 内层循环条件是 j >= h,h = 4,进行第一轮循环后,j = j - h = 5 - 4 = 1,不满足循环条件,内外层for 循环结束
  • 缩小跨度 h
 h = h / 3;

上述步骤总结:从 ”标红“ 的描述大家可以看到,按照计算出的跨度 h 值 4,进行跨度区间的数据交换,尽可能的让大的数据往后面排,减少数据交换的次数,也就是减少了内存的操作次数,提升了性能。

4、第一次 while 循环结束,h = h / 3 = 4 / 3 = 1,进行第二轮 while 循环

4.1、第一次外循环条件为:i = h = 1

  • nums = [6, 5 , 4, 3, 2, 1]
  • 第一次内循环初始条件为:j = i = 1,j >= h(h = 1),比较 nums[ j ] = 1 和 nums[ j - h = 0] = 2 ,1 < 2 交换位置,1和2之间的跨度为 1

此时 nums 如下:
nums[0] = 1, nums[1] = 2,nums[2] = 4,nums[3] = 3,nums[4] = 6,nums[5] = 5

  • 最后 j = j - h = 0 不满足循环,内层循环退出

4.2、第二次外循环条件为:i++ 后 i = 2

  • 第一次内循环条件为:j = i = 2,j >= h (h = 1),比较 nums[ j = 2] = 4 和 nums[ j - h = 1] = 2,4 不小于2,第一次内循环结束
  • 第二次内循环条件为:j = i = 1, j >= h (h = 1), 比较 nums[ j ] = 2 和 nums[ j - h = 0] = 1,2 不小于 1,第二次内循环结束
在步骤4.1,因为nums 索引 2 之前的数据都排序好了,所以插入排序在这里不满足排序条件,什么都不做

4.3、第三次外循环条件为:i++ 后 i = 3

  • nums = [6, 5 , 4, 3, 2, 1]
  • 第一次内循环条件为:j = i = 3,j >= h (h = 1), 比较 nums[ j ] = 3 和 nums[ j - h = 2] = 4,3 < 4 交换位置,3和4之间的跨度为 1
  • 此时 nums 如下:
    nums[0] = 1,nums[1] = 2,nums[2] = 3nums[3] = 4,nums[4] = 6,nums[5] = 5
  • 之后和上面的步骤 4.2 一样,根据跨度为1,“逆向” 依次比较 j 前面的数,这里大家应该可以看到和插入排序的操作是没什么区别的
  • 因为不满足交换条件,所以内层循环结束

4.4、第四次外循环条件为:i++ 后 i = 4

  • 第一次内循环条件为:j = i = 4, j >= h (h = 1), 比较 nums[ j ] = 6 和 nums[ j - h = 3] = 4,6 不小于 4 后续循环也不会满足交换条件
  • 循环退出

4.5、第五次外循环条件为:i++ 后 i = 5

  • nums = [6, 5 , 4, 3, 2, 1]
  • 第一次内循环条件为:j = i = 5, j >= h (h = 1), 比较 nums[ j ] = 5 和 nums[ j - h = 4] = 6 ,5 < 6 交换位置,5和5之间跨度为 1
    此时 nums 如下:
    nums[0] = 1,nums[1] = 2,nums[2] = 3,nums[3] = 4,nums[4] = 5nums[5] = 6
  • 排序完成,后续的循环不满足交换条件,退出while 循环

上述总结:每次进行while 循环都是在“缩小”跨度 h ,然后对 “跨度h” 内的数据按照插入排序算法进行排序

😊哈哈,相信聪明的你看完瓜瓜的文章,对希尔排序算法应该有更深的理解了吧~,创作不易,如果觉得有帮助到你,希望点赞收藏哦!若有错误,欢迎指正,非常感谢!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为你解答关于希尔排序的问题。希尔排序是插入排序的一种改进算法,也被称为“缩小增量排序”。它的基本思想是将待排序的序列按照一定的间隔分成若干个子序列,对每个子序列进行插入排序,然后逐步缩小间隔,直到间隔为1,最后对整个序列进行一次插入排序。 希尔排序的时间复杂度与间隔序列的选择有关,最坏时间复杂度为$O(n^2)$,平均时间复杂度为$O(n \log n)$。相比于插入排序,希尔排序的时间复杂度有了明显的提升,且其在实际应用中也表现得比插入排序好。 下面是希尔排序的示例代码: ```python def shell_sort(arr): n = len(arr) gap = n // 2 while gap > 0: for i in range(gap, n): temp = arr[i] j = i while j >= gap and arr[j - gap] > temp: arr[j] = arr[j - gap] j -= gap arr[j] = temp gap //= 2 return arr ``` 在这段代码中,我们首先定义了一个希尔排序的函数shell_sort,它接收一个列表arr作为参数,并返回排好序的列表。在函数中,我们首先获取列表的长度n和初始的间隔gap,然后开始循环,直到间隔为1为止。在每次循环中,我们将列表按照间隔分成若干个子序列,对每个子序列进行插入排序,将子序列按照升序排列。最后,我们将间隔除以2,继续循环直到间隔为1。 使用希尔排序对列表进行排序非常简单,只需要调用shell_sort函数即可。例如,我们可以这样调用函数: ```python arr = [5, 2, 8, 3, 1, 6] sorted_arr = shell_sort(arr) print(sorted_arr) ``` 这段代码会输出排好序的列表[1, 2, 3, 5, 6, 8]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值