转载请注明出处:http://blog.csdn.net/a740169405/article/details/50718458
思想:
希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小, 插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比O(n^2)好一些。
换个方式理解,就是每次都把数组分成多个小数组(虚拟的)小数组里的每个元素其实是大数组里跳跃一定维度的元素集合。
循环实现:
/** * 希尔排序 * * @param arr 数组 */
private static void shellSort(int[] arr) {
int i, j;
int tmp;
int increment = arr.length;
do {
increment = increment / 3 + 1;
for (i = increment; i < arr.length; i++) {
j = i - increment;
tmp = arr[i];
while (j >= 0 && tmp < arr[j]) {
arr[j + increment] = arr[j];
j -= increment;
}
arr[j + increment] = tmp;
}
} while (increment > 1);
}
我们发现,其实希尔排序就是在直接插入排序的基础上加入了一个increment,也就是步长/增量。
并在往前跳跃的时候,其跳跃值改为increment。
递归方式:
/** * 希尔排序 * * @param arr 数组 */
private static void shellSort(int[] arr, int increment) {
int i, j;
int tmp;
increment = increment / 3 + 1;
for (i = increment; i < arr.length; i++) {
j = i - increment;
tmp = arr[i];
while (j >= 0 && tmp < arr[j]) {
arr[j + increment] = arr[j];
j -= increment;
}
arr[j + increment] = tmp;
}
if (increment <= 1) {
return;
}
shellSort(arr, increment);
}
调用代码:
int[] arr = new int[] {1, 45, 78, 23, 12, 98, 150, 1, 45};
shellSort(arr);
System.out.println(Arrays.toString(arr));
int[] array = new int[] {2, 5, 90, 78, 12, 90, 67, 89, 2, 1};
shellSort(array, array.length);
System.out.println(Arrays.toString(array));
复杂度分析:
这里的增量不一定是3,当增量序列为:
时,可以获得不错的效果,其时间复杂度为
要比时间复杂度为n² 的算法(插入/冒泡等)效率高
稳定性分析:
因为希尔排序是跳跃式的插入排序,所以是有可能打乱相同大小的元素顺序,所以是不稳定的算法