排序--希尔排序
图片转载于https://www.cnblogs.com/chengxiao/p/6104371.html
1、什么是希尔排序?
希尔排序也是一种插入排序,他是第一个打破时间复杂度O(n^2)的排序方法,它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
2、希尔排序的思想:
希尔排序是把元素按下标的一定增量进行分组,对每组使用直接插入排序算法排序;
随着增量逐渐减少,当增量减至 1 时,整个文件恰被分成一组,算法便终止
3、代码逐步实现:
排序的元素: int[] arr={8,9,1,7,2,3,5,4,6,0};
3.1 交换法实现
//第一步 for (int i=5;i<arr.length;i++){ //i的初始值为初始增量 10/2=5,分为5组,每组两个元素 for (int j=i-5;j>=0;j-=5){ //j是距离i为5元素,那么,0和5一组,6和2一组,以此类推,每组比完之后,回退到上一组重新比较,具体用法看第二轮 if (arr[j+5]<arr[j]){ //比较大小,交换 temp=arr[j]; arr[j]=arr[j+5]; arr[j+5]=temp; } } } System.out.println(Arrays.toString(arr));
//第二次 for (int i=2;i<arr.length;i++){ //这里的2是上次的5/2=2,所以分为两组,一组5个 for (int j=i-2;j>=0;j-=2){//距离为2的元素,j-=2是每次比完这一轮重新指向上一分组比较,例如[3,1]和[1,0]两组,比完[1,0]是[0,1],在和前面比较排序,最后为[0,1,3] if (arr[j+2]<arr[j]){ temp=arr[j]; arr[j]=arr[j+2]; arr[j+2]=temp; } } } System.out.println(Arrays.toString(arr));
//第三次 for (int i=1;i<arr.length;i++){ //i是2/2=1,一共是一组 for (int j=i-1;j>=0;j-=1){ if (arr[j+1]<arr[j]){ temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } System.out.println(Arrays.toString(arr));
最后把上面的代码整合起来:
//汇总(交换法,花费时间长) for (int a=arr.length/2;a>0;a/=2){ //a是增量 for (int i=a;i<arr.length;i++){ for (int j=i-a;j>=0;j-=a){ if (arr[j+a]<arr[j]){ temp=arr[j]; arr[j]=arr[j+a]; arr[j+a]=temp; } } } System.out.println(Arrays.toString(arr));
上面才用交换的方式实现的排序花费时间大,不推荐使用,按照交换的思路继续,替换成插入法
3.2 插入法实现:
1 //汇总(基于插入,花费时间短) 2 for (int gap=arr.length/2;gap>0;gap/=2){ 3 for (int i=gap;i<arr.length;i++){ 4 int j=i-gap; 5 int temp=arr[i]; 6 while (j>=0 && temp<arr[j]){ 7 arr[j+gap]=arr[j]; 8 j-=gap; 9 } 10 arr[j+gap]=temp; 11 } 12 System.out.println(Arrays.toString(arr)); 13 14 }
从3-10行都是插入法来实现的,可以看出,希尔排序就是对排序的元素进行分组,大大提升了时间
4、时间复杂度
O(n^(1.3—2))
5、希尔的优势
希尔排序其实就是在插入排序的基础上,增加了一个增量,每次为元素划分不同的组
希尔排序在无序的时候,分组多,每个组元素少
随着增量的变化,分组变少,每个组内元素增加,但组内元素也逐渐变得有序
所以排序起来快(如果原始数据的大部分元素有序,那么插入排序会很快)