希尔排序.
创始人
2024-04-04 04:31:04

希尔排序

简单的插入排序存在的问题

我们看简单的插入排序可能存在的问题
数组arr={2,3,4,5,6,1},这个时候需要插入的数1(最小),这样的过程是:
{2,3,4,5,6,6}
{2,3,4,5,5,6}
{2,3,4,4,5,6}
{2,3,3,4,5,6}
{2,2,3,4,5,6}
{1,2,3,4,5,6}
,我们明显上面排序是从小到大,明显最后一个如果较小,那么我们移动的次数会很多,对效率有印象,所以对于这样的方式,我们提出来一个方案,希尔排序

希尔排序法介绍

希尔排序(Donald Shell)于1959年提出的一种排序算法,希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序

希尔排序法基本思想

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序,随着增加量逐渐减少,每组包含的关键词越来越多,每当增量减至1时,整个文件恰好被分为一组

希尔排序图解

在这里插入图片描述
在这里插入图片描述
希尔排序时,我们用两种方法.

  • 对有序序列在插入时采用交互法,并测试排序速度
  • 对有序序列在插入时采用移动发,并测试排序速度

交换法的希尔排序

逐步推到方法


package sort;import java.util.Arrays;public class ShellSort {public static void main(String[] args) {int[] arr={8,9,1,7,2,3,5,4,6,0};shellSort(arr);}//使用逐步推到的方式来编写我们的Shell排序public static void shellSort(int[] arr){int temp=0;//希尔排序的第一轮排序/*思路* 1,因为第一轮排序,是将十个数据分成了五组,那么这个时候我们就按五组进行处理*/for (int i=5;i//遍历各组中所有的元素(共五组,每组有两个元素),步长是5for (int j=i-5;j>=0;j-=5){//如果当前的元素,大于加上步长后的那个元素,说明需要交换if(arr[j]>arr[j+5]){temp=arr[j];arr[j]=arr[j+5];arr[j+5]=temp;}}}System.out.println("希尔排序一轮后输出:"+ Arrays.toString(arr));//希尔排序的第二轮排序/*思路* 1,因为第二轮排序,我们缩小增量,原来的增量在除以2,此时是2.5,取整数,2*/for (int i=2;i//遍历各组中所有的元素(共五组,每组有两个元素),步长是5for (int j=i-2;j>=0;j-=2){//如果当前的元素,大于加上步长后的那个元素,说明需要交换if(arr[j]>arr[j+2]){temp=arr[j];arr[j]=arr[j+2];arr[j+2]=temp;}}}System.out.println("希尔排序二轮后输出:"+ Arrays.toString(arr));//希尔排序的第三轮排序/*思路* 1,因为第二轮排序,我们缩小增量,原来的增量在除以2,此时是1,*/for (int i=1;i//遍历各组中所有的元素(共五组,每组有两个元素),步长是5for (int j=i-1;j>=0;j-=1){//如果当前的元素,大于加上步长后的那个元素,说明需要交换if(arr[j]>arr[j+1]){temp=arr[j];arr[j]=arr[j+1];arr[j+1]=temp;}}}System.out.println("希尔排序三轮后输出:"+ Arrays.toString(arr));}
}

通过逐步推到方式,有很多人在第一次看代码的时候,逐步推到都用到了两个for循环,为什么还能解决简单插入排序产生的问题,其实,我们在开始分成产生我们的第一个增量的时候,我们就对大小做了一次,调整,所有我们后来每一次,内循环中的if条件是几乎不怎么进去的,所有我们更本不会做if条件里面的那些交换,就解决了简单插入排序产生的交换次数过多的问题.

Shell Sorting

package sort;import java.util.Arrays;public class ShellSort {public static void main(String[] args) {int[] arr={8,9,1,7,2,3,5,4,6,0};shellSort(arr);}//使用逐步推到的方式来编写我们的Shell排序public static void shellSort(int[] arr){int temp=0;//根据前面的逐步分析,我们使用循环处理,gap是我们的增量值for(int gap=arr.length/2;gap>0;gap/=2){for (int i=gap;i//遍历各组中所有的元素(共五组,每组有两个元素),步长是5for (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;}}}System.out.println("希尔排序x轮后输出:"+ Arrays.toString(arr));}
}}

但是我们的上面的插入法的希尔排序其实比我们简单的插入排序更加耗时,时间复杂度更大,这个是为什么呢?因为我们虽然没有走if里面的,但是我们走了三个for循环,而且,我们发现一个还是进行了一次交换,也是要耗费时间的.我们的简单插入法,我们发现一个比较大的并没有交换,而是移位,然后再到满足我们插入条件的时候才插入.

移动法的希尔排序

package sort;import java.util.Arrays;public class ShellSort {public static void main(String[] args) {int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};shellSort2(arr);//选择排序的速度测试int[] arr2 = new int[80000];for (int i = 0; i < 80000; i++) {arr2[i] = (int) (Math.random() * 40000);//生成一个[0,20000)的随机整数}long startTime = System.currentTimeMillis();shellSort2(arr2);long endTime = System.currentTimeMillis();System.out.println("排序用的时间:" + (endTime - startTime));
}//对交换式的希尔排序进行优化,->移位置法
public static void shellSort2(int[] arr){//增量gap,并逐步缩小增量for (int gap=arr.length/2;gap>0;gap/=2){//从第gap个元素,逐个对其所在的组进行直接插入排序for (int i=gap;iint index=i;//待插入的iint temp=arr[index]; //此时arr[i]的值if(arr[index]while ((index-gap)>=0&&temp//移动arr[index]=arr[index-gap];index-=gap;//index往前面移动}//当退出我们while循环后就给temp找到l插入的位置arr[index]=temp;}}}System.out.println(Arrays.toString(arr));
}
}

从上面的两个希尔排序看出,我使用移位的希尔排序才提升的速度不是一点点.

相关内容

热门资讯

财联社1月8日早间新闻精选 转自:财联社【财联社1月8日早间新闻精选】 1、工业和信息化部等八部门印发《“人工智能+制造”专项行...
国家医保局:2028年前全面推... 转自:北京日报客户端今后看病缴费将不用再为排长队发愁了。1月8日,国家医保局发布通知,将在全国范围内...
新闻分析丨格陵兰岛为何让美国如... 来源:新华社新华社北京1月7日电 新闻分析|格陵兰岛为何让美国如此垂涎新华社记者林昊美军强行控制委内...
数字人主播纳入监管 “会员降权...   市场监管总局和国家网信办近日联合发布《网络交易平台规则监督管理办法》《直播电商监督管理办法》。这...
突破困境 “丫邦”组合更加坚定 北京时间1月7日,马来西亚羽毛球公开赛混双首轮,2号种子蒋振邦/魏雅欣2比0击败印度组合卡普尔/加德...