# 希尔排序

提示:希尔排序的理论有一定难度,不感兴趣的朋友不需要深入研究。

# 本节内容概括

  • 希尔排序是插入排序的优化,利用的是插入排序的重要意义:在小数组(几乎有序的数组)上表现良好;
  • 通过「分组插入排序」使得数组变得逐步有序;
  • 最后一轮执行标准的插入排序。

# 视频教程

建议快进播放。

首先复习一下「插入排序」在什么情况下效率高呢?

  • 在待排序数组「基本有序」的时候;
  • 在待排序数组的元素个数较少的时候,一个经验值是

# 希尔排序的基本思想

开始的时候逐渐让数组变得基本有序,最后使用一次使用「插入排序」就变得高效了。

  • 「逐渐让数组变得基本有序」的方法是让移动的「步幅」增大,不是一步一步挪过去,而是「大步流星」、「连蹦带跳」走过去;
  • 「逐渐缩小增量」「分组实施插入排序让数组变得逐渐接近有序」「最后执行一次标准的插入排序」( 最后一轮就是「原汁原味」的插入排序。

「希尔排序」的实现比较多,我们这里只选取希尔排序的一种比较容易理解的实现。「希尔排序」也可以理解为「分组插入排序」。

希尔是计算机科学家的名字,所以希尔排序就得换一个名字来记。

希尔排序是 「分组插入排序」 或者 「带间隔的插入排序」。好处是:让较小的元素一下子来到数组的前面

每一轮完成一次分组插入排序以后,数组就朝着接近有序的方向前进了一步。最后一轮一定是一次标准的插入排序。

# 通过实例理解「希尔排序」的基本思想

  • 第 1 轮:把下标间隔为 5 的元素分成一组,一共 5 组,分别执行插入排序

此时数组比未排序的时候更接近有序了一点。

  • 第 2 轮:把下标间隔为 2 的元素分成一组,一共 2 组,分别执行插入排序

此时数组比第 2 轮排序开始之前更接近有序了一点。

  • 第 3 轮:把下标间隔为 1 的元素分成一组,其实就是标准的插入排序。

参考代码

public class Solution {

    public int[] sortArray(int[] nums) {
        int len = nums.length;
        for (int detal = len / 2; detal > 0; detal /= 2) {
            for (int start = 0; start < detal; start++) {
                insertionSortForDetal(nums, len, detal, start);
            }
        }
        return nums;
    }

    private void insertionSortForDetal(int[] nums, int len, int detal, int start) {
        for (int i = start + detal; i < len; i += detal) {
            int temp = nums[i];
            int j = i;
            for (; j - detal >= 0; j -= detal) {
                if (nums[j - detal] > temp) {
                    nums[j] = nums[j - detal];
                } else {
                    break;
                }
            }
            // 此时 nums[j - 1] <= temp
            // nums[j] 的值被赋值到了 nums[j + 1]
            nums[j] = temp;
        }
    }
}

复杂度分析:(已经超出本教程讲解的范围,感兴趣的朋友可以查阅相关资料,例如维基百科、《算法导论》《算法(第 4 版)》等学术著作。)


作者:liweiwei1419 链接:https://suanfa8.com/basic-sorting-algorithm/shell/introduction 来源:算法吧 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Last Updated: 11/18/2024, 11:23:03 PM