【恋上数据结构】希尔排序

简介: 【恋上数据结构】希尔排序

我的《恋上数据结构》源码(第1季 + 第2季):https://github.com/szluyu99/Data_Structure_Note

经典的十大排序算法!
在这里插入图片描述

前言

请==务必==看一下这个:排序算法前置知识+代码环境准备

当上面的内容都准备好以后,那就开始希尔排序吧!

希尔排序思路

希尔排序把序列看作是一个矩阵,分成 𝑚 列,逐列进行排序

  • 𝑚 从某个整数逐渐减为1
  • 当 𝑚 为1时,整个序列将完全有序

因此,希尔排序也被称为递减增量排序(Diminishing Increment Sort)

矩阵的列数取决于步长序列(step sequence):

  • 不同的步长序列,执行效率也不同

实例图解

希尔本人给出的步长序列是 𝑛 / 2^𝑘^,比如 𝑛 为16时,步长序列是 { 1, 2, 4, 8 }

假设有如下序列:{ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }
在这里插入图片描述
按照步长序列,首先分为8列,对每一列进行排序
在这里插入图片描述
然后分为4列,对每一列进行排序
在这里插入图片描述
然后分为 2 列,对每一列进行排序
在这里插入图片描述
最后分为 1 列,变成升序序列。
在这里插入图片描述
不难看出来,从8列变为1列的过程中,逆序对的数量在逐渐减少

还记得插入排序的这个性质吗:

  • 插入排序的时间复杂度与逆序对的数量成正比关系

逆序对的数量越多,插入排序的时间复杂度越高。

因此希尔排序底层一般使用插入排序对每一列进行排序,可以认为希尔排序是插入排序的改进版。

列的划分思路

假设有11个元素,步长序列是 {1, 2, 5}
在这里插入图片描述
假设元素在第 col 列、第 row 行,步长(总列数)是 step

  • 那么这个元素在数组中的索引是 row * step + col
  • 比如 9 在排序前是第 0 行、第 2 列,那么它排序前的索引是 0 * 5 + 2 = 2
  • 比如 4 在排序前是第 1 行、第 2 列,那么它排序前的索引是 1 * 5 + 2 = 7

步长序列计算代码

使用希尔本人给出的步长序列: 𝑛 / 2^𝑘^ ,比如 𝑛 为16时,步长序列是 { 1, 2, 4, 8 }

/**
 * 希尔本人提出的步长序列
 */
public List<Integer> shellStpSequence(){
    List<Integer> stepSequence = new ArrayList<>();
    int step = array.length; // 16
    while((step >>= 1) > 0){ // 8 4 2 1
        stepSequence.add(step);
    }
    return stepSequence;
}

希尔排序完整实现

/**
 * 希尔排序
 */
public class ShellSort <T extends Comparable<T>> extends Sort<T>{

    @Override
    protected void sort() {
        // 根据元素数量算出步长序列
        List<Integer> stepSequence = shellStpSequence();
        // 按步长序列划分进行排序
        for (Integer step : stepSequence) {
            sort(step); // 按step进行排序
        }
    }
    
    /**
     * 分成step列进行排序
     */
    private void sort(int step){
        // col: 第几列, column的简称
        for(int col = 0; col < step; col++){
            // 插入排序对每一列进行排序
            for(int begin = col + step; begin < array.length; begin += step){
                // col、col+step、col+2*step、col+3*step
                int cur = begin;
                while(cur > col && cmp(cur, cur - step) < 0){
                    swap(cur, cur - step);
                    cur -= step;
                }
                
            }
        }
    }
    
    /**
     * 希尔本人提出的步长序列
     */
    public List<Integer> shellStpSequence(){
        List<Integer> stepSequence = new ArrayList<>();
        int step = array.length;
        while((step >>= 1) > 0){
            stepSequence.add(step);
        }
        return stepSequence;
    }
    
}

将速率过慢的几个排序去掉,只比较有可比性的几个排序。
生成 100000 个取值在[1, 10000] 的随机数进行排序:
在这里插入图片描述

步长序列优化

目前已知的最好的步长序列最坏情况时间复杂度是 O(n^4/3^) ,1986年由 Robert Sedgewick 提出
在这里插入图片描述
在这里插入图片描述

/**
 * 目前效率最高的步长序列
 */
private List<Integer> sedgewickStepSequence() {
    List<Integer> stepSequence = new LinkedList<>();
    int k = 0, step = 0;
    while (true) {
        if (k % 2 == 0) {
            int pow = (int) Math.pow(2, k >> 1);
            step = 1 + 9 * (pow * pow - pow);
        } else {
            int pow1 = (int) Math.pow(2, (k - 1) >> 1);
            int pow2 = (int) Math.pow(2, (k + 1) >> 1);
            step = 1 + 8 * pow1 * pow2 - 6 * pow2;
        }
        if (step >= array.length) break;
        stepSequence.add(0, step);
        k++;
    }
    return stepSequence;
}

注:只是提高了最坏和平均时间复杂度,但是没有突破最好时间复杂度O(n)。
在这里插入图片描述

插入排序优化

上面代码中的插入排序是无优化的插入排序,可以通过二分搜索优化插入排序。
具体见这个:插入排序及二分搜索优化

复杂度和稳定性

  • 最好情况是步长序列只有1,且序列几乎有序,时间复杂度为 O(n)
  • 最坏和平均时间复杂度取决步长序列, 范围在 O(n^3/4^) ~ O(n^2^)
  • 空间复杂度为O(1)
  • 希尔排序属于不稳定排序
相关文章
|
7月前
|
算法 搜索推荐 Java
数据结构与算法(Java篇)笔记--希尔排序
数据结构与算法(Java篇)笔记--希尔排序
|
7月前
|
机器学习/深度学习 算法 搜索推荐
数据结构实验之排序六:希尔排序
数据结构实验之排序六:希尔排序
|
2月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
27 1
|
6月前
|
算法 搜索推荐
数据结构算法--6 希尔排序和计数排序
**希尔排序**是插入排序的改进版,通过分组插入来提高效率。它逐步减少元素间的间隔(增量序列),每次对每个间隔内的元素进行插入排序,最终增量为1时进行最后一次直接插入排序,实现整体接近有序到完全有序的过程。例如,对数组`5, 7, 4, 6, 3, 1, 2, 9, 8`,先以间隔`d=4`排序,然后`d=2`,最后`d=1`,完成排序。计数排序则适用于0到100的数值,通过统计每个数出现次数,创建对应计数数组,再根据计数重建有序数组,时间复杂度为`O(n)`。
|
5月前
|
搜索推荐 测试技术
【数据结构常见七大排序(一)】—插入排序篇【直接插入排序】And【希尔排序】
【数据结构常见七大排序(一)】—插入排序篇【直接插入排序】And【希尔排序】
|
7月前
|
存储 搜索推荐 算法
[数据结构]————排序总结——插入排序(直接排序和希尔排序)—选择排序(选择排序和堆排序)-交换排序(冒泡排序和快速排序)—归并排序(归并排序)
[数据结构]————排序总结——插入排序(直接排序和希尔排序)—选择排序(选择排序和堆排序)-交换排序(冒泡排序和快速排序)—归并排序(归并排序)
|
7月前
|
C语言
【C语言/数据结构】排序(直接插入排序|希尔排序)
【C语言/数据结构】排序(直接插入排序|希尔排序)
47 4
|
6月前
|
算法 Shell C语言
数据结构与算法——希尔排序(引例、希尔增量序列、原始希尔排序、代码、时间复杂度、Hibbard增量序列、Sedgewick增量序列)
数据结构与算法——希尔排序(引例、希尔增量序列、原始希尔排序、代码、时间复杂度、Hibbard增量序列、Sedgewick增量序列)
66 0
|
6月前
|
存储 搜索推荐
深入了解数据结构第四弹——排序(1)——插入排序和希尔排序
深入了解数据结构第四弹——排序(1)——插入排序和希尔排序
30 0
|
7月前
|
存储 算法 搜索推荐
【数据结构与算法】:插入排序与希尔排序
欢迎大家来到初阶数据结构的最后一小节:排序
【数据结构与算法】:插入排序与希尔排序