希尔排序(Shell Sort)
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
算法描述
- 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列个数k,对序列进行k 趟排序;
- 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
例子
数组: 8 9 1 7 2 3 5 4 6 0
缩小增量: gap = length/2 = 5
分组: [8,3] [9,5] [1,4] [7,6] [2,0]
第一次: 3 5 1 6 0 8 9 4 7 2
缩小增量: gap = gap/2 = 5/2 = 2
分组: [3,1,0,9,7] [5,6,8,4,2]
第二次: 0 2 1 4 3 5 7 6 9 8
缩小增量: gap = gap/2 = 2/2 = 1
第三次: 0 1 2 3 4 5 6 7 8 9
结束
其实主要就是插入排序加上了增量分组进行排序。
算法复杂度
空间复杂度: O(1)
时间复杂度:
排序不稳定,原来相等的两个参数排在前面可能会排在前面。
代码实现
public static void shellSort(int[] arr) {
int len = arr.length;
for (int gap =len / 2; gap > 0; gap = gap / 2) {
for (int i = gap; i < len; i++) {
int j = i;
int current = arr[i];
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
}
System.out.println(Arrays.toString(arr));
}
}
运行结果
输入数组:int[] arr = {8,9,1,7,2,3,5,4,6,0};
[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]
[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
但是按照上面的步骤,这时候我们可以看到和演算结果一致。