希尔排序
在说希尔排序之前我们来看看插入排序存在的效率问题:
可以看出当插入排序要插入的数比较小的时候,我们需要对数组进行多次后移,这样就会对效率有很大影响。
插入排序对于小规模的数据或者是基本有序时很高效,数据有序程度越高,插入排序的效率越高,希尔排序正是利用了这一点。
-
希尔排序介绍
希尔排序是希尔与1959年提出的一种排序算法,希尔排序也是一种插入排序,它的简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。 -
希尔排序思想
- 设待排序元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为increment个子序列,所有距离为increment的元素放在同一个子序列中,在每一个子序列中分别实行直接插入排序。然后缩小间隔increment,重复上述子序列划分和排序工作。直到最后取increment=1,将所有元素放在同一个子序列中排序为止。
- 由于开始时,increment的取值较大,每个子序列中的元素较少,排序速度较快,到排序后期increment取值逐渐变小,子序列中元素个数逐渐增多,但由于前面工作的基础,大多数元素已经基本有序,所以排序速度仍然很快。
-
希尔排序示意图
-
希尔排序代码实现
public class ShellSort {
public static void main(String[] args) {
int[] array = {8,9,1,7,2,3,5,4,6,0};
sort(array);
System.out.println(Arrays.toString(array));
}
public static void sort(int[] array) {
// 需要进行次数,每次增量都除以二
for (int increment = array.length/2; increment > 0; increment = increment/2) {
// 遍历,进行排序
for (int i = 0; i < array.length - increment; i++) {
int insertVal = array[i + increment];
int insertIndex = i;
// 插入排序,每次都是通过increment递减
for (int j = i ; j >= 0; j = j - increment) {
if (array[j] > insertVal) {
if (j - increment < 0) {
insertIndex = j;
}
array[j + increment] = array[j];
} else {
insertIndex = j + increment;
break;
}
}
if (insertIndex != i + increment) {
array[insertIndex] = insertVal;
}
}
}
}
}
排序结果
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
下面我们对希尔排序的效率进行测试
public static void main(String[] args) {
// int[] array = {8,9,1,7,2,3,5,4,6,0};
int[] array = new int[80000];
for (int i = 0; i < array.length; i++) {
// 随机生成一个0到8000000的随机数
Random random = new Random();
int nextInt = random.nextInt(8000000);
array[i] = nextInt;
}
// 排序前时间,h毫秒
long beforeSortTimeMillis = System.currentTimeMillis();
sort(array);
// 排序后时间
long afterSortTimeMillis = System.currentTimeMillis();
System.out.println("排序总共花费时间为:" + (afterSortTimeMillis - beforeSortTimeMillis) + "毫秒");
// System.out.println(Arrays.toString(array));
运行结果:
排序总共花费时间为:20毫秒
从结果我们可以看到对8万个数据进行排序,希尔排序才用了20毫秒,而插入排序,选择排序(可以参考我的文章插入排序与选择排序)需要2000毫秒,说明希尔排序对大数量的排序比较友好,如果要排序的数据量比较大我们可以考虑希尔排序。