您现在的位置是:首页 >其他 >希尔排序详解(Shell Sort)网站首页其他

希尔排序详解(Shell Sort)

武梓龙_Arvin 2023-07-06 19:13:41
简介希尔排序详解(Shell Sort)
本文已收录于专栏
《算法合集》

一、简单释义

1、算法概念

  希尔排序是插入排序的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。

2、算法目的

  把无序数组通过分组,分组之间比较进行移动,最后形成一个有序数组  (文中以升序为例)

3、算法思想

  先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2,以此类推。

二、核心思想

  1. –对已有的数列进行分组,明确增量;
  2. –每个分组使用直接插入排序进行位置交换;
  3. –将每个分组执行直接插入排序后的结果在进行直接插入排序;

三、图形展示

在这里插入图片描述
  1、第一次排序:首先明确第一次分组的增量值,用数组的的长度/2。6/2=3,将数组分为增量为3的三个分组,三个分组使用直接插入排序进行位置交换
在这里插入图片描述

  2、第二次排序:首先根据第一次的增量来计算第二次分组的增量,用第一次的增量/2得到第二次的增量,然后进行分组,分组完毕之后使用直接插入排序交换位置。
在这里插入图片描述

  3、第三次排序:首先根据第二次的增量来计算第三次分组的增量,直到增量为1进行最后一次的排序。

四、代码实现

/**
 * @BelongsProject: demo
 * @BelongsPackage: com.wzl.Algorithm.InsertionSort
 * @Author: Wuzilong
 * @Description: 希尔排序
 * @CreateTime: 2023年5月1日
 * @Version: 1.0
 */

public class ShellSort {

    public static void main(String[] args) {
        int[] arr = {3, 5, 9, 2, 4, 7};
        System.out.println("排序之前数组:");
        System.out.println(Arrays.toString(arr));
        //希尔排序
        insertionSort(arr);

        System.out.println("希尔排序后数组:");
        System.out.println(Arrays.toString(arr));

    }

    private static int[]  insertionSort(int[] arr){
        if(arr == null || arr.length <= 1){
            return arr;
        }
        //希尔排序  升序
        for (int d = arr.length / 2;d>0;d /= 2){ //d:增量  7   3   1
            System.out.println("增量取值:" + d);
            for (int i = d; i < arr.length; i++){
                //i:代表即将插入的元素角标,作为每一组比较数据的最后一个元素角标
                //j:代表与i同一组的数组元素角标
                for (int j = i-d; j>=0; j-=d){ //在此处-d 为了避免下面数组角标越界
                    if (arr[j] > arr[j + d]) {// j+d 代表即将插入的元素所在的角标
                        //符合条件,插入元素(交换位置)
                        swap(arr,j,j+d);
                    }
                }
            }
        }
        return arr;
    }

    public static void swap(int[] arr,int a,int b)
    {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

运行结果
在这里插入图片描述

五、算法描述

1、问题描述

  每一步将一个待排序的元素,按其排序码的大小,插入到前面已经排好序的一组元素的适当位置上去,直到元素全部插入为止

2、算法过程

整个算法过程分为以下几步:
  1)通过数组的长度/2得到第一趟排序的增量,按照增量进行分组。
  2)每个分组使用直接插入排序进行位置的交换
  3)通过第一趟排序的增量/2得到第二次排序的增量,向上取整,在按照增量进行分组
  4)每个分组使用直接插入排序进行位置的交换
  5)直到得到的增量为1时,进行的直接插入排序的结果为希尔排序的结果。

3、算法总结

  直接插入排序是由两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较,直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。

六、算法分析

1、时间复杂度

  首先直接插入排序是一个稳定的排序算法;最好的情况下,也就是排序本身是有序的,共需比较n-1次,因为没有移动的记录,时间复杂度为O(n)。最坏的情况下,即排序表是逆序的情况,时间复杂为O(n²)。

2、空间复杂度

  算法的空间复杂度并不是计算实际占用的空间,而是计算整个算法的辅助空间单元的个数。在直接插入排序中只使用了i,j,temp这三个辅助空间单元,所以空间复杂度是O(1)。

3、算法稳定性

  由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。