希尔排序是对插入排序的优化,假如一组数据,最小值在末尾,那么插排的效率较低,需要大量的移动。
希尔排序针对此进行了优化,1959年一个叫shell的哥们,想出了间隙排序法(大牛的脑子就是不一样),啥意思呢?就是把一组数据,通过一定的间隙,看成不同的数组,然后每一组数据在进行插排,间隙为1的的希尔排序就是插排。
来个图:~~
这个图就是把10个数据分为了5组,然后每2个一小组,每组进行插排,采用的是折半法,间隙为5。10/2
然后把排完序的数组在进行分组,折半思想,间隙为2,每5个一组,进行插排。
5/2
最后在进行分组,间隙为1,最后这次就是普通的插排
2/2
由此可见:
数组长度为10,在折半思想的套路下,三次即可完成排序呢
上代码:
1.希尔排序之交换法
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[8000000];
for (int i = 0; i < 8000000; i++) {
arr[i]=(int)(Math.random()*800000000);
}
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH mm ss");
String format = sdf.format(date);
System.out.println(format);
/*System.out.println(Arrays.toString(arr));*/
int temp = 0;
boolean flag = false;
//gap为多少组,/2为每一组的个数
//最小分组>0,1/2==0.5,将不满足,说明以无法再细分了,循环结束,排序完成
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
//gap为多少组,每次循环排序一组
for (int i = gap; i < arr.length; i++) {
//遍历每组中的所有元素,步长为gap
for (int j = i - gap; j >= 0; j -= gap) {
if (arr[j] > arr[j + gap]) {
flag = true;
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}else {
break;
}
}
}
}
Date date2 = new Date();
String format2 = sdf.format(date2);
System.out.println(format2);
}
800万数据5S
2.希尔排序之位移法
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[8000000];
for (int i = 0; i < 8000000; i++) {
arr[i] = (int) (Math.random() * 800000000);
}
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH mm ss");
String format = sdf.format(date);
System.out.println(format);
/*System.out.println(Arrays.toString(arr));*/
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; i++) {
//保存待插入的数
int j = i;
//临时变量保存该值
int temp = arr[j];
//找位置,当前的数小于前面对应的数,这里j是后面的数
if (arr[j] < arr[j - gap]) {
//只要待插入的数【j】 - 步长>=0,说明还能继续找位置
while (j - gap >= 0 && temp < arr[j - gap]) {
//移动,当前的数被前面大的数覆盖呢
arr[j] = arr[j - gap];
//控制下标越界,每发现一个,交换完成往前移动一个步长
j -= gap;
}
//退出循环后即找到位置
arr[j] = temp;
}
}
/* System.out.println(Arrays.toString(arr));*/
}
Date date2 = new Date();
String format2 = sdf.format(date2);
System.out.println(format2);
}
}
800万数据4S
每次折半其实不是最好的间隙方法, 唐纳德·克努特提出了 Kunth序列,即
h=1;
h=3*h+1;
这个序列是根据数组长度动态的划分间隙,提高效率呢