一、简单释义
1、算法概念
希尔排序是插入排序的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
2、算法目的
把无序数组通过分组,分组之间比较进行移动,最后形成一个有序数组 (文中以升序为例)
3、算法思想
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2,以此类推。
二、核心思想
先–对已有的数列进行分组,明确增量;
中–每个分组使用直接插入排序进行位置交换;
后–将每个分组执行直接插入排序后的结果在进行直接插入排序;
三、图形展示
宏观展示
微观展示
以3、5、9、2、4、7这个数组为例,进行每一步排序的拆分。
1、第一次排序:首先明确第一次分组的增量值,用数组的的长度/2。6/2=3,将数组分为增量为3的三个分组,三个分组使用直接插入排序进行位置交换
2、第二次排序:首先根据第一次的增量来计算第二次分组的增量,用第一次的增量/2得到第二次的增量,然后进行分组,分组完毕之后使用直接插入排序交换位置。
3、第三次排序:首先根据第二次的增量来计算第三次分组的增量,直到增量为1进行最后一次的排序。
四、算法实现
实现思路
将图形化展示的过程转换成对应的开发语言,本文中主要以Java语言为例来进行算法的实现。
1、定义一个list集合用来存储待排序的数
2、获取待排序中的中间值作为分组的增量值
3、分组完成之后进行第二次获取增量分组
4、以此类推,直到增量值为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排序是不稳定的。