【十大排序算法系列】希尔排序

本文介绍了希尔排序算法,它是插入排序的优化版。希尔排序通过定义步长将序列分组排序,不断改变步长,直到步长为1时对整个序列排序。其时间复杂度最差为O(n^2),最好为O(n),平均为O(n^1.3),空间复杂度为O(1),还给出了Java代码实现。

写在前面

  • 上一篇更新了这个系列的排序算法(【十大排序算法系列】插入排序)。分析了插入排序的流程逻辑以及代码实现,下面来写下希尔排序
  • 照例给出系列内所有算法的对比。。
  • 常见的十大排序算法有:冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序等。

常见的十大排序算法,时间复杂度和空间复杂度如下图:
在这里插入图片描述


希尔排序

介绍
  • 希尔(Shell)排序又称为缩小增量排序,它是一种插入排序,算是直接插入排序算法的一种优化版。
  • 由DL.Shell于1959年提出而得名
  • 希尔排序的基本思想是,定义一个步长,然后根据步长把序列分成一个一个子组,然后对每个组使用直接排序算法进行排序,接着继续改变步长,重复上述逻辑,直到步长为 1 ,对整个序列进行直接排序,由于这时候序列基本有序了,所以此时插入排序算法的效率较高。
  • 希尔排序的时间复杂度最差为O(n^2),最好情况时O(n),平均时间复杂度为O(n^1.3)。希尔排序空间复杂度O(1)。
逻辑

希尔排序算法是插入排序的一种优化,直接插入排序的话,如果序列没什么有序的规则,则这时候进行插入排序复杂度将会很高。那么希尔排序的一些做法是,先对序列进行一些预处理,即先把元素步长分组内的元素进行排序,对多个组进行排序以后,当最后步长为1,则序列全部元素为一个组,此时序列已基本有序,只需要进行少量的元素交换即可完成最终序列的排序。

动态图

希尔排序动态图
在这里插入图片描述

关于步长

步长的选择有争议,也有很多种说法,这里只采用 不断除以2 的方式。
初始步长 = 序列的长度 / 2

Java代码实现
import java.util.Arrays;
import java.util.Objects;

/**
 * 希尔排序.
 *
 * @author linzp
 * @version 1.0.0
 * CreateDate 2021/1/7 9:04
 */
public class ShellSort {

    public static void main(String[] args) {
        int[] array = new int[]{1, 7, 4, 6, 3, 5};
        Arrays.stream(array).forEach(System.out::print);
        shellSort(array);
        System.out.println();
        Arrays.stream(array).forEach(System.out::print);
    }

    /**
     * 希尔排序算法逻辑.
     * 序列进行初步处理,使其大概有序.
     * 即根据步长分组,对每组依次进行直接插入排序.
     *
     * @param array
     */
    public static void shellSort(int[] array) {

        if (Objects.isNull(array) || array.length <= 0) {
            return;
        }

        //获取步长(希尔增量),初始一般为数组长度/2.
        int gap = array.length;
        //当步长大于1,不断进行除以2处理
        while (gap > 1) {
            gap = gap / 2;
            //根据步长分组,对所有分组进行处理
            for (int i = 0; i < gap; i++) {
                //对当前分组内的元素进行直接插入排序处理
                for (int j = i + gap; j < array.length; j = j + gap) {
                    int temp = array[j];
                    int k;
                    //直接插入排序判断,是否大于当前元素,不断往后腾位置
                    for (k = j - gap; k >= 0 && array[k] > temp; k = k - gap) {
                        array[k + gap] = array[k];
                    }
                    array[k + gap] = temp;
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林志鹏JAVA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值