希尔排序是插入排序的改进,按增量分组并逐次缩小至1进行插入排序;Knuth序列(h=3h+1)最常用,初始h通过循环确定,再以h为步长做插入排序。
希尔排序的基本思想与数组实现
希尔排序是插入排序的改进版本,核心在于将原数组按一定间隔(增量)分组,对每组进行插入排序,再逐步缩小增量直到为1。java中用一维数组即可完成,关键在增量序列的选择和分组逻辑。
经典Knuth序列的实现与说明
最常用且稳健的增量序列是Knuth序列:h = 3h + 1,从1开始反向生成不超过数组长度的最大值。例如长度为10的数组,生成过程为 1 → 4 → 13(超限),故取 h = 4,再取 h = 1。
- 先计算初始增量:int h = 1; while (h
- 外层循环控制增量递减:for (; h >= 1; h /= 3)
- 内层按h为步长做插入排序:从索引h开始,逐个将arr[i]插入到其所在h-间隔子序列的正确位置
增量序列对性能的影响
希尔排序的时间复杂度高度依赖增量序列。不同序列带来显著差异:
- 希尔原始序列(N/2, N/4, …):最坏情况仍为O(N²),已不推荐
- Knuth序列(1, 4, 13, 40, …):理论界为O(N3/2),实践中稳定高效,适合通用场景
- Sedgewick序列(1, 5, 19, 41, …):形如4ᵏ + 3×2ᵏ⁻¹ + 1,平均性能更优,但实现稍复杂
- 动态序列(如Hibbard:2ᵏ−1):保证O(N3/2),但常数因子略大
完整可运行示例(Knuth序列)
以下是一个简洁、带注释的Java数组实现:
public static void shellSort(int[] arr) {
if (arr == null || arr.length <= 1) return;
<pre class="brush:php;toolbar:false;">// 1. 生成最大合法Knuth增量
int h = 1;
while (h < arr.length / 3) h = h * 3 + 1;
// 2. 按h分组,逐步缩小至1
for (; h >= 1; h /= 3) {
// 对每个h-间隔子序列做插入排序
for (int i = h; i < arr.length; i++) {
int temp = arr[i];
int j = i;
// 在子序列中向前查找插入位置(步长为h)
while (j >= h && arr[j - h] > temp) {
arr[j] = arr[j - h];
j -= h;
}
arr[j] = temp;
}
}}
立即学习“Java免费学习笔记(深入)”;
调用 shellSort(new int[]{64, 34, 25, 12, 22, 11, 90}) 即可验证排序效果。


















