希尔排序(Shell Sort)是一种改进的插入排序算法,也称为“缩小增量排序”, 是非稳定排序算法。希尔排序是基于插入排序的以下两点性质而提出改进方法的:
1、插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
2、但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
希尔排序的基本思想是通过比较一定间隔(称为增量)的元素进行排序,并逐步减小增量,最终使整个序列变为有序。希尔排序的具体步骤如下:
1、首先确定一个增量序列(通常为n/2,n/4,...,1),然后按照这个增量序列分组。
2、对每一组使用插入排序算法进行排序。
3、逐步缩小增量,重复步骤2,直到增量为1时,排序结束。
执行过程请移步文章末尾:排序执行过程。
希尔排序的时间复杂度取决于增量序列的选取,理论上最坏情况下的时间复杂度为O(n^2),但在实际应用中,由于希尔排序的增量序列具有一定规律,因此其平均时间复杂度往往要优于简单插入排序,而且它在处理较大数据集合时比直接插入排序快得多。
AI编码实现:
本地测试:
为了能够打印排序过程,代码稍作修改。
package com.algorithm.sort;
import java.util.Arrays;
/**
* @author LuoFei
* @className: ShellSort
* @projectName algorithm
* @description: TODO
* @date 2023/2/20 12:56
*/
public class ShellSort {
public static void shellSort(int[] arr) {
int n = arr.length;
// 计算初始增量序列
int gap = n/3;
while (gap > 0) {
System.out.println("增量步数:"+gap);
//对每个增量分组使用插入排序
for (int i= gap; i < n; i++) {
System.out.println("第"+(i-gap+1)+"轮");
int temp = arr[i];
System.out.println("选择"+i+"号位数字“"+temp+"”为基准数字,与前面已排序数字比较");
int j = i;
//对组内元素进行插入排序
while (j >= gap) {
System.out.print("比较:["+(j-gap)+", "+i+"]");
if (arr[j - gap] <= temp) {
System.out.println(", 顺序正确");
break;
}
System.out.println(", "+(j - gap)+" 号位后移"+gap+"位;");
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
System.out.println("基准数字”"+temp+"“插入"+j+"号位置");
System.out.println("新数组:"+ Arrays.toString(arr));
System.out.println("------------------------------------------");
}
//缩小增量序列
System.out.println("==========================================");
gap /= 2;
}
}
public static void main(String[] args) {
int[] arr = {5, 2, 8, 3, 9, 1};
System.out.println("希尔排序");
System.out.println("初始数组:"+ Arrays.toString(arr));
System.out.println("==========================================");
shellSort(arr);
System.out.print("最终数组:"+Arrays.toString(arr));
}
}
排序执行过程:
希尔排序
初始数组:[5, 2, 8, 3, 9, 1]
==========================================
增量步数:2
第1轮
选择2号位数字“8”为基准数字,与前面已排序数字比较
比较:[0, 2], 顺序正确!
基准数字”8“插入2号位置
新数组:[5, 2, 8, 3, 9, 1]
------------------------------------------
第2轮
选择3号位数字“3”为基准数字,与前面已排序数字比较
比较:[1, 3], 顺序正确!
基准数字”3“插入3号位置
新数组:[5, 2, 8, 3, 9, 1]
------------------------------------------
第3轮
选择4号位数字“9”为基准数字,与前面已排序数字比较
比较:[2, 4], 顺序正确!
基准数字”9“插入4号位置
新数组:[5, 2, 8, 3, 9, 1]
------------------------------------------
第4轮
选择5号位数字“1”为基准数字,与前面已排序数字比较
比较:[3, 5], 3 号位后移2位;
比较:[1, 5], 1 号位后移2位;
基准数字”1“插入1号位置
新数组:[5, 1, 8, 2, 9, 3]
------------------------------------------
==========================================
增量步数:1
第1轮
选择1号位数字“1”为基准数字,与前面已排序数字比较
比较:[0, 1], 0 号位后移1位;
基准数字”1“插入0号位置
新数组:[1, 5, 8, 2, 9, 3]
------------------------------------------
第2轮
选择2号位数字“8”为基准数字,与前面已排序数字比较
比较:[1, 2], 顺序正确!
基准数字”8“插入2号位置
新数组:[1, 5, 8, 2, 9, 3]
------------------------------------------
第3轮
选择3号位数字“2”为基准数字,与前面已排序数字比较
比较:[2, 3], 2 号位后移1位;
比较:[1, 3], 1 号位后移1位;
比较:[0, 3], 顺序正确!
基准数字”2“插入1号位置
新数组:[1, 2, 5, 8, 9, 3]
------------------------------------------
第4轮
选择4号位数字“9”为基准数字,与前面已排序数字比较
比较:[3, 4], 顺序正确!
基准数字”9“插入4号位置
新数组:[1, 2, 5, 8, 9, 3]
------------------------------------------
第5轮
选择5号位数字“3”为基准数字,与前面已排序数字比较
比较:[4, 5], 4 号位后移1位;
比较:[3, 5], 3 号位后移1位;
比较:[2, 5], 2 号位后移1位;
比较:[1, 5], 顺序正确!
基准数字”3“插入2号位置
新数组:[1, 2, 3, 5, 8, 9]
------------------------------------------
==========================================
最终数组:[1, 2, 3, 5, 8, 9]