总结完直接插入排序之后接着就能接着总结一下希尔排序,希尔排序也是插入排序的一种,属于优化过的插入排序。
希尔排序(Shell Sort)
之所以叫做希尔排序,是因为这个排序算法是DL.Shell 于 1959 年提出而得名。
其排序原理为将一个无序数组先进行分组,然后每个分组分别执行直接插入排序,之后再次分组,再次直接插入排序直到排序完成。
希尔排序没有具体的分组数据长度要求,但是通常我们选取整体数组长度/2为首次分组间隔,如数组长度为9,那么我就用4进行分组即:
第一次分组,分组跨度为4
第一组
iArrays[0],iArrays[4],iArrays[8]
第二组
iArrays[1],iArrays[5]
第三组
iArrays[2],iArrays[6]
第四组
iArrays[4],iArrays[8]
将4个小组分别执行直接插入排序,直接插入排序之后。
第二次分组,用之前的分组间隔(4)/2,就是2,结果就是
第一组
iArrays[0],iArrays[2],iArrays[4],iArrays[6],iArrays[8]
第二组
iArrays[1],iArrays[3],iArrays[5],iArrays[7]
再将两组进行插入排序。
第三次分组,分组间隔为上次的分组间隔(2)/2,结果就是1
只有唯一的一组 iArrays[0],iArrays[1],iArrays[2],iArrays[3],iArrays[4],iArrays[5],iArrays[6],iArrays[7],iArrays[8]
再将该组进行插入排序。
我们先看一下整体的效果图:
希尔排序其实就是在原本的外层循环之外再次嵌套一层循环,并且修改每次比较的最内层循环的判断逻辑,先把代码直接展示出来:
public static void shellSort(int[] iArrays){
//循环整体数据
for(int gap = iArrays.length/2 ; gap>0 ; gap/=2) {
for (int i = gap; i <iArrays.length; i++) {
for(int j = i;j-gap>=0 && iArrays[j]<iArrays[j-gap];j-=gap){
swap(iArrays,j,j - 1);
}
}
}
}
可以看到内两层的循环其实基本和原本的直接插入排序是几乎一样的,区别就在于之前直接排序最内层每次比较的递进是1,就是1和2比2和3比,而希尔排序中跨步是根据循环进行修改的,也就是说比如最开始数组长度为8,那么跨步就是4,a[0]就是和a[4]去比较,第二层循环是每次递增关系。
举个例子说跨步长度为4的话
第一次比较的就是a[4]和a[0]
第二次比较a[5]和a[1]
第三次比较的是a[6]和a[2]
第四次比较的是a[7]和a[3]
第五次比较的是a[8]和a[4]
此时出现不同第六次比较的不是a[9]和a[5]而是
a[4]和a[0]
因为之前4次比较每次第三层循环走一次就结束了,而当i递增到8的时候会需要和4比较之后依旧满足4-4>=0,所以会将4和0去比较
其实就是一个比较优化过的直接插入排序。
因为直接插入排序对于越是有序的数组效率越高,所以使用这种方式会使得排序算法更加优化。
好,我的话说完了,这次没有gif了。