希尔排序
希尔排序(Shell Sort)是插入排序的一种。因 D.L.Shell 于 1959 年提出而得名。
希尔排序思路
基本思想:将整个待排序记录序列分割为若干个子序列,然后对每一个子序列进行直接插入排序.
算法思路:
1. 先取一个正整数 d1(d1 < n),把全部记录分成 d1 个组,所有距离为 d1 的倍数的记录看成一组,然后在各组内进行插入排序
2. 然后取 d2(d2 < d1)
3. 重复上述分组和排序操作;直到取 di = 1(i >= 1) 位置,即所有记录成为一个组,最后对这个组进行插入排序。一般选 d1 约为 n/2,d2 为 d1 /2, d3 为 d2/2 ,…, di = 1。
希尔排序运行过程
注:运行过程摘自一篇博客
假设有数组 array = [80, 93, 60, 12, 42, 30, 68, 85, 10],首先取 d1 = 4,将数组分为 4 组,如下图中相同颜色代表一组:
然后分别对 4 个小组进行插入排序,排序后的结果为:
然后,取 d2 = 2,将原数组分为 2 小组,如下图:
然后分别对 2 个小组进行插入排序,排序后的结果为:
最后,取 d3 = 1,进行插入排序后得到最终结果:
希尔排序代码
- (void)dShellSort:(NSMutableArray *)array {
if (array.count <= 1) {
return;
}
NSInteger increment = array.count / 2;
while (increment >= 1) {
for (NSInteger i = increment; i < array.count; i ++) {
// 避免移动数据过程中将数据弄丢,将要排序的数据存储为临时变量
float target = [array[i] floatValue];
NSInteger j = i - increment ;
if (target < [array[j] floatValue]) {
// 目标数据需要移动,前方有序数据依次向后移动,同时通过j>0保证数组不发生越界
while (j >= 0 && target < [array[j] floatValue]) {
[array exchangeObjectAtIndex:j + increment withObjectAtIndex:j];
j = j - increment;
};
// 将数据插入正确位置
array[i - increment] = @(target);
}
}
increment = increment/2;
}
}
性能(算法时间、空间复杂度、稳定性)分析
时间复杂度
希尔排序的时间复杂度与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量的希尔排序的时间复杂度为O(N3/2)。空间复杂度
空间复杂度为O(1)。稳定性
希尔排序是不稳定的。