希尔排序(Shell Sort)是一种改进的插入排序算法,能够提高插入排序的效率。它通过将数组分成若干个子序列,对每个子序列进行插入排序,从而使得数据更加有序。希尔排序的核心思想是通过逐步减少间隔来使得数据元素逐渐接近最终排序状态。
增量设置方案:
增量呈递减方式,直至增量为1,一般增n至1之间。
过程图表:
存储数组:
00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
84 | 92 | 78 | 67 | 21 | 79 | 23 | 57 | 86 | 32 | 46 | 19 | 22 | 90 | 15 | 69 | 42 | 13 | 47 | 38 | 55 | 34 | 18 | 43 | 26 | 94 | 72 | 62 |
从数组下标0开始,依次增加9
增量 H=9
1 | 84 32 47 62 | 32 47 62 84 |
2 | 92 46 38 | 38 46 92 |
3 | 78 19 55 | 19 55 78 |
4 | 67 22 34 | 22 34 67 |
5 | 21 90 18 | 18 21 90 |
6 | 79 15 43 | 15 43 79 |
7 | 23 69 26 | 23 26 69 |
8 | 57 42 94 | 42 57 94 |
9 | 86 13 72 | 13 72 86 |
00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | |
84 | 92 | 78 | 67 | 21 | 79 | 23 | 57 | 86 | 32 | 46 | 19 | 22 | 90 | 15 | 69 | 42 | 13 | 47 | 38 | 55 | 34 | 18 | 43 | 26 | 94 | 72 | 62 | |
H=9 | 32 | 38 | 19 | 22 | 18 | 15 | 23 | 42 | 13 | 47 | 46 | 55 | 34 | 21 | 43 | 26 | 57 | 72 | 62 | 92 | 78 | 67 | 90 | 79 | 69 | 94 | 86 | 84 |
从数组下标0开始,依次增加5
增量 H=5
1 |
32 15 46 26 78 94 |
15 26 32 46 78 94 |
2 |
38 23 55 57 67 86 |
23 38 55 57 67 86 |
3 |
19 42 34 72 90 84 |
19 34 42 72 84 90 |
4 |
22 13 21 62 79 |
13 21 22 62 79 |
5 |
18 47 43 92 69 |
18 43 47 69 92 |
00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | |
84 | 92 | 78 | 67 | 21 | 79 | 23 | 57 | 86 | 32 | 46 | 19 | 22 | 90 | 15 | 69 | 42 | 13 | 47 | 38 | 55 | 34 | 18 | 43 | 26 | 94 | 72 | 62 | |
H=9 | 32 | 38 | 19 | 22 | 18 | 15 | 23 | 42 | 13 | 47 | 46 | 55 | 34 | 21 | 43 | 26 | 57 | 72 | 62 | 92 | 78 | 67 | 90 | 79 | 69 | 94 | 86 | 84 |
H=5 | 15 | 23 | 19 | 13 | 18 | 26 | 38 | 34 | 21 | 43 | 32 | 55 | 42 | 22 | 47 | 46 | 57 | 72 | 62 | 69 | 78 | 67 | 84 | 79 | 92 | 94 | 86 | 90 |
从数组下标0开始,依次增加3
增量 H=3
1 | 15 13 38 43 42 46 62 67 92 90 |
13 15 38 42 43 46 62 67 90 92 |
2 | 23 18 34 32 22 57 69 84 94 |
18 22 23 32 34 57 69 84 94 |
3 |
19 26 21 55 47 72 78 79 86 |
19 21 26 47 55 72 78 79 86 |
00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | |
84 | 92 | 78 | 67 | 21 | 79 | 23 | 57 | 86 | 32 | 46 | 19 | 22 | 90 | 15 | 69 | 42 | 13 | 47 | 38 | 55 | 34 | 18 | 43 | 26 | 94 | 72 | 62 | |
H=9 | 32 | 38 | 19 | 22 | 18 | 15 | 23 | 42 | 13 | 47 | 46 | 55 | 34 | 21 | 43 | 26 | 57 | 72 | 62 | 92 | 78 | 67 | 90 | 79 | 69 | 94 | 86 | 84 |
H=5 | 15 | 23 | 19 | 13 | 18 | 26 | 38 | 34 | 21 | 43 | 32 | 55 | 42 | 22 | 47 | 46 | 57 | 72 | 62 | 69 | 78 | 67 | 84 | 79 | 92 | 94 | 86 | 90 |
H=3 | 13 | 18 | 19 | 15 | 22 | 21 | 38 | 23 | 26 | 42 | 32 | 47 | 43 | 34 | 55 | 46 | 57 | 72 | 62 | 69 | 78 | 67 | 84 | 79 | 90 | 94 | 86 | 92 |
从数组下标0开始,依次增加1
增量 H=1
00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | |
84 | 92 | 78 | 67 | 21 | 79 | 23 | 57 | 86 | 32 | 46 | 19 | 22 | 90 | 15 | 69 | 42 | 13 | 47 | 38 | 55 | 34 | 18 | 43 | 26 | 94 | 72 | 62 | |
H=9 | 32 | 38 | 19 | 22 | 18 | 15 | 23 | 42 | 13 | 47 | 46 | 55 | 34 | 21 | 43 | 26 | 57 | 72 | 62 | 92 | 78 | 67 | 90 | 79 | 69 | 94 | 86 | 84 |
H=5 | 15 | 23 | 19 | 13 | 18 | 26 | 38 | 34 | 21 | 43 | 32 | 55 | 42 | 22 | 47 | 46 | 57 | 72 | 62 | 69 | 78 | 67 | 84 | 79 | 92 | 94 | 86 | 90 |
H=3 | 13 | 18 | 19 | 15 | 22 | 21 | 38 | 23 | 26 | 42 | 32 | 47 | 43 | 34 | 55 | 46 | 57 | 72 | 62 | 69 | 78 | 67 | 84 | 79 | 90 | 94 | 86 | 92 |
H=1 | 13 | 15 | 18 | 19 | 21 | 22 | 23 | 26 | 32 | 34 | 38 | 42 | 43 | 46 | 47 | 55 | 57 | 62 | 67 | 69 | 72 | 78 | 79 | 84 | 86 | 90 | 92 | 94 |
注意:无论增量怎样设置,最后都必须有增量1。
希尔排序代码与直接插入排序代码即为相似。
简易代码描述:
void Shell_sort(int a[],int d[],int n,int t)
{
int i,j,h,k,x;
for(h=0;h<t;h++)
{
k=d[h];
for(i=k;i<n;i++)
{
x=a[i];
for(j=i-k;j>=0&&x<a[j];j-=k)
{
a[j+k]=a[j];
}
a[j+k]=x;
}
}
}
代码分析:
-
参数说明:
a[]
:待排序数组。d[]
:间隔序列。n
:数组的长度。t
:间隔序列的长度。
-
间隔序列的处理:
- 外层循环
for(h=0; h<t; h++)
遍历间隔序列d[]
。 k = d[h]
获取当前间隔值。
- 外层循环
-
排序过程:
- 对于每个间隔值
k
,从k
开始,使用插入排序算法对相应的子数组进行排序。 x = a[i]
保存当前元素的值。- 内层循环
for(j=i-k; j>=0 && x<a[j]; j-=k)
用于查找插入位置并移动元素。 a[j+k] = x
将x
插入到正确的位置。
- 对于每个间隔值
时间复杂度:
- 希尔排序的时间复杂度与间隔序列的选择密切相关。最坏情况下,时间复杂度可以达到 (O(n^2)),而最好的情况通常在 (O(n \log n)) 左右。不同的间隔序列能显著影响排序的效率。通过使用希尔排序,可以显著减少插入排序的平均时间复杂度,尤其是对大规模数据集来说。