赞
踩
希尔排序从原理上看是插入排序的升级版。
如上图所示,希尔排序首先选择一个步长(假设gap=4)。先把{9,5,10,1}这四个数按照插入排序排好位置,然后再将第二组{6,12,15,13}也按照插入排序排好,后面重复以4为步长组合的数组插入排序。
经过第一轮以4为间隔的组合数组排序后,这个数组就会变得基本有序了。但是也只是基本有序,所以还需要再次缩小步长继续重复上述插入排序,直到步长为1的时候就是插入排序了。
为什么希尔排序的效率比插入排序高?
1. 先写出插入排序算法,固定一个步长的算法
public static void shellSort(int[] arrays) {
int gap = 4;
for (int i = gap; i < arrays.length; i++) {
for (int j = i; j > gap-1; j-=gap) {
if (arrays[j] < arrays[j - 1]) {
swap((arrays, j, j - 1);
}
}
}
}
2. 逐渐缩短步长,直到步长等于1变成插入排序
public static void shellSort(int[] arrays) {
for (int gap = 4; gap > 0; gap /= 2) {
for (int i = gap; i < arrays.length; i++) {
for (int j = i; j > gap - 1; j -= gap) {
if (arrays[j] < arrays[j - 1]) {
swap((arrays, j, j - 1);
}
}
}
}
}
3. 对于比较长的数组,比如亿级别的,4这个步长还是太小了。步长越小,移动的次数也就越多。所以可以用二分法来取它的步长
public static void shellSort(int[] arrays) {
for (int gap = arrays.length >> 1; gap > 0; gap /= 2) {
for (int i = gap; i < arrays.length; i++) {
for (int j = i; j > gap - 1; j -= gap) {
if (arrays[j] < arrays[j - 1]) {
swap((arrays, j, j - 1);
}
}
}
}
}
4. 修改gap 使得算法更快更高效,国际上对步长有一个公式,如下
继续优化算法为:
public static void shellSort(int[] arrays) {
int h = 1;
while (h <= arrays.length) {
h = 3 * h + 1;
}
for (int gap = h; gap > 0; gap = (gap - 1)/ 3) {
for (int i = gap; i < arrays.length; i++) {
for (int j = i; j > gap - 1; j -= gap) {
if (arrays[j] < arrays[j - 1]) {
swap((arrays, j, j - 1);
}
}
}
}
}
- 希尔排序是跳着排序的,所以不稳定
- 时间复杂度,目前国际上算出的最平均的复杂度是O(n^1.3),证明略…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。