希尔排序是在插入排序的基础上对插入排序进行了优化。我们知道插入排序的过程是将后面的要排序的数字依次和待排序前面的数字进行比较,然后判断大小,最后在进行交换。
这就存在一个很大的问题,就是如果最小的数字在最右边的话,按照我们排序的要求(顺序排列)这个最小的数字要依次和前面的n-1个数字进行比较,然后复制交换,所以插入排序的最大的缺点就是复制的次数过多。
实际上我们可以在直接进行插入排序之前对数据进行“处理”,所谓的“处理”就是让数据变得有序一些,不那么随机化,希尔排序也就做了这样一件事情,使用了一个“增量”,用这个“增量”来对待排序的数组进行分组(比如对10个数据进行排序,按照增量为4来分,就可以分别对下标为(0,4,8)(1,5,9)的两组数据进行小规模的排序)在这个小的规模的数组中采用直接插入排序的方法将小的数组排好序,然后将增量减小,再重复进行,最后当增量减小到1的时候就进行最后的一次排序,和我们以前的插入排序是一样的方法,只不过这次插入排序是在经过我们前面处理之后才进行的,进过前面的处理,数据基本上已经达到了有序了,所以在最后一次进行插入排序的时候复制量就减小了很多,大大的提高了效率,时间效率虽然不及快排,但是比直接插入排序还是快了很多。
代码:
package 希尔排序; /** * 希尔排序 * * @author TMs * */ public class ShellSort { public static int count = 0; public static void main(String[] args) { int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 }; print(data); shellSort(data); print(data); } public static void shellSort(int[] data) { // 计算出最大的h值 int h = 1; while (h <= data.length / 3) { h = h * 3 + 1; } while (h > 0) { for (int i = h; i < data.length; i += h) { if (data[i] < data[i - h]) { int tmp = data[i]; int j = i - h; while (j >= 0 && data[j] > tmp) { data[j + h] = data[j]; j -= h; } data[j + h] = tmp; print(data); } } // 计算出下一个h值 h = (h - 1) / 3; } } public static void print(int[] data) { for (int i = 0; i < data.length; i++) { System.out.print(data[i] + "\t"); } System.out.println(); } }
打印输出结果:
5 3 6 2 1 9 4 8 7 1 3 6 2 5 9 4 8 7 1 2 3 6 5 9 4 8 7 1 2 3 5 6 9 4 8 7 1 2 3 4 5 6 9 8 7 1 2 3 4 5 6 8 9 7 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9