希尔排序(缩小增量排序算法):比较次数和移动次数均有改善。主要是利用直接插入排序的最好性质:元素少且基本有序。
希尔排序思想:
-
将记录序列分成若干个子序列分别进行直接插入排序;
-
经过多次调整序列记录已基本有序最后再对记录进行直接插入排序。
具体如下:
-
对整个文件,按步长d1分组,组内进行直接插入排序;
-
取d2<d1(缩小增量),继续以d2为步长排序,直到dt=1(此时进行直接插入排序)为止。
所谓步长 : 就是两个元素的下标的差值 , 例如 , 若步长为 4( 元素下标从 0 或 1 均可 ), 第 1 个元素 、 第 5 个元素会在一组 , 一次类推 。
待排序序列:46, 55, 13, 42, 94, 17, 5, 70
d1= 4:(46, 17, 5, 42, 94, 55, 13, 70)
d2= 2:(5, 17, 13, 42, 46, 55, 94, 70)
d3= 1:(5, 13, 17, 42, 46, 55, 70, 94)
distance=4 46,17,5,42,94,55,13,70,
distance=2 5,17,13,42,46,55,94,70,
distance=1 5,13,17,42,46,55,70,94,
证明希尔排序的性能需要用到逆转数的概念。
时间复杂度:O(n1.5)。
稳定性:不稳定,举一个反例即可。例如:(2, 4, 1, 2)
希尔排序的java代码实现如下:
java
public class ShellSort {
public static void shellSort(int[] sourceArray) {
int len = sourceArray.length;
// 起始增量(步长)
int distance = len / 2;
while (distance >= 1) {
// 本次增量情况下的循环组数,每一组进行直接插入排序
for (int groupidx = 0; groupidx < distance; groupidx++) {
// 组内进行直接插入排序
for (int idx = groupidx + distance; idx < len; idx += distance) {
// 正在遍历的元素
int monitor = sourceArray[idx];
/* while循环寻找每一组的插入位置 */
// 索引j表示每一组到这个位置都是排好序的
int j = idx - distance;
while ((j >= 0) && (sourceArray[j] > monitor)) {
// 移动元素
sourceArray[j + distance] = sourceArray[j];
j -= distance;
}
sourceArray[j + distance] = monitor;
}
}
// 增量缩小
distance /= 2;
}
}
public static void main(String[] args) {
// int[] sourceArray = { 46, 55, 13, 42, 94, 17, 5, 70 };
int[] sourceArray = { 19, 2, 3, 6, 1, 8, 13 };
shellSort(sourceArray);
for (int tmp : sourceArray) {
System.out.print(tmp + " ");
}
}
}