希尔排序
基本介绍
希尔排序是希尔(DonaldShell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。
插入排序文章:插入排序
希尔排序法基本思想:
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便停止。
希尔排序算法的过程
原始数组:8 9 1 7 2 3 5 4 6 0
初始增量 gap = length / 2 = 5,意味着整个数组被分为5组,[8,3] [9,5,] [1,4] [7,6] [2,0]
对这5组分班进行直接插入排序,结果如下,可以看到,像3,5,6这些小元素,都被调到了前面,然后缩小增量gap = 5 / 2 = 2,数组被分为 2 组 [3,1,0,9,7] [5,6,8,4,2]
进行一轮之后:3 5 1 6 0 8 9 4 7 2
对以上2组再分班进行直接插入排序,结果如下,可以看到,此时整个数组的有序成都更进一步,再缩小增量gap = 2 / 2 = 1,此时,整个数组为1组[0,2,1,4,3,5,7,6,9,8]
又进行一轮之后:0 2 1 4 3 5 7 6 9 8
经过上面的“宏观调控”,整个数组的有序化程度成果喜人。此时,仅仅需要对以上数列简单微调,无序大量移动操作即可完成整个数组的排序。
最终结果: 0 1 2 3 4 5 6 7 8 9
代码实现交换法(不推荐使用)
package sort;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
//int[] arr1 = {8,9,1,7,2,3,5,4,6,0};
//测试希尔排序速度,给80000个数据,测试
//创建一个80000个随机的数组
int[] arr = new int[80000];
for (int i = 0;i < 80000;i ++) {
//会生成一个[0,8000000]的数
arr[i] = (int)(Math.random() * 8000000);
}
//System.out.println("最开始的数组为:" + Arrays.toString(arr));
Date date1 = new Date();
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat1.format(date1);
System.out.println("排序前的时间:" + date1Str);
//测试希尔排序
shellSort(arr);
Date date2 = new Date();
String date2Str = simpleDateFormat1.format(date2);
System.out.println("排序后的时间:" + date2Str);
}
public static void shellSort(int[] arr) {
int temp = 0;
//设置每次的步长,如第一次分为五组,则步长为5
for (int gap = arr.length / 2;gap > 0;gap /= 2) {
for (int i = gap;i < arr.length;i ++) {
//遍历每组的元素(gap组,每组**个元素,步长gap)
for (int j = i - gap;j >= 0;j -= gap) {
//如果前面的数大于后面的数,则交换位置
if (arr[j] > arr[j + gap]) {
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
}
}
}
不推荐原因:未使用到插入排序的思想,而是使用的冒泡排序思想,导致运行速度负提示。
代码实现移动法(推荐使用)
package sort;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
//int[] arr1 = {8,9,1,7,2,3,5,4,6,0};
//测试希尔排序速度,给80000个数据,测试
//创建一个80000个随机的数组
int[] arr = new int[80000];
for (int i = 0;i < 80000;i ++) {
//会生成一个[0,8000000]的数
arr[i] = (int)(Math.random() * 8000000);
}
//System.out.println("最开始的数组为:" + Arrays.toString(arr));
Date date1 = new Date();
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat1.format(date1);
System.out.println("排序前的时间:" + date1Str);
//测试希尔排序
shellSort(arr);
Date date2 = new Date();
String date2Str = simpleDateFormat1.format(date2);
System.out.println("排序后的时间:" + date2Str);
}
public static void shellSort(int[] arr) {
//设置每次的步长,如第一次分为五组,则步长为5
for (int gap = arr.length / 2;gap > 0;gap /= 2) {
//从第gap元素,逐个对其所在的组进行直接插入排序
for (int i = gap;i < arr.length;i ++) {
int j = i;
int temp = arr[j];
if (arr[j] < arr[j - gap]) {
while (j - gap >= 0 && temp < arr[j - gap]) {
//移动
arr[j] = arr[j - gap];
j -= gap;
}
//当退出循环之后,就给temp找到了插入的位置
arr[j] = temp;
}
}
}
}
}
笔记源自:韩顺平数据结构与算法