希尔排序

Posted mango-tree

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了希尔排序相关的知识,希望对你有一定的参考价值。

希尔排序

前面我们说过了插入排序,它是三种基本排序中最常用的一种排序,具有排序稳定,空间复杂度低,而且在样本小且基本有序时效率比较高,该篇讲述的希尔排序是对插入排序的一种优化排序,在希尔排序开始阶段,通过增量的方式使排序的样本小化,在希尔排序的最后阶段蜕变成插入排序,但可以完美实现样本基本有序,从而使得对样本的排序相比于直接使用插入排序,在很大程度上得到优化。
希尔排序中存在一个关键因素——增量,通过增量的存在将原数组分解成多个子数组,然后在每个子数组中使用插入排序来使元素有序化,一轮排序过后,缩小增量值,按上述方式继续对重新得到的子数组进行排序,最后增量会变为1,此时就是对整个数组进行最后的一轮排序,最后得到的就是经过希尔排序之后的有序数组。
假定初始数组为:{2,5,7,1,3,4,6}
技术图片
人为设置初始增量为4,那么得到的四个子数组为:{2,3}、{5,4}、{7,6}、{1}
技术图片
每个子数组经过插入排序之后得到的数组为:{2,4,6,1,3,5,7}
技术图片
将增量变为2,那么得到的两个子数组为:{2,6,3,7}、{4,1,5}
技术图片
每个子数组经过插入排序之后得到的数组为:{2,1,3,4,6,5,7}
技术图片
将增量变为1,进行最后一轮的插入排序得到的结果为:{1,2,3,4,5,6,7}
技术图片
对应的算法代码为:

private static void shell(int[] arr) {
    int gap = 4;
    for (; gap >= 1; gap >>= 1) {
        for (int i = gap; i < arr.length; i++) {
            for (int j = i; j > gap - 1; j -= gap) {
                if (arr[j - gap] > arr[j]) {
                    Utils.swap(arr, j - gap, j);
                }
            }
        }
    }
}

希尔排序关键的一点就在于增量的选择,直接使用1,2,4,8,16...的方式并不能最大限度的提高希尔排序的效率,网上也有很多其他的增量序列可以选择,这里提供一种Knuth序列的实现方式

//Knuth序列
n=1
n=3*n+1
序列:1,4,13,40,121...

使用Knuth序列对应的希尔排序代码为:

private static void shell(int[] arr) {
    int gap = 1;
    while (gap < arr.length / 3) {
        gap = gap * 3 + 1;//按照Knuth序列增大增量值
    }
    for (; gap >= 1; gap = (gap - 1) / 3) {//按照Knuth序列减小增量值
        for (int i = gap; i < arr.length; i++) {
            for (int j = i; j > gap - 1; j -= gap) {
                if (arr[j - gap] > arr[j]) {
                    Utils.swap(arr, j - gap, j);
                }
            }
        }
    }
}

通过对数器的方式进行排序结果的验证

//测试代码
public static void main(String[] args) {
    int size = 15;
    int[] arr1 = Utils.generateRandomArray(size, 100);
    int[] arr2 = new int[size];
    System.arraycopy(arr1, 0, arr2, 0, size);
    System.out.println("原数组:			" + Arrays.toString(arr1));
    Arrays.sort(arr1);
    System.out.println("系统方法排序后:	" + Arrays.toString(arr1));
    shell(arr2);
    System.out.println("希尔方法排序后:	" + Arrays.toString(arr2));
}
原数组:		[70, 49, 88, 24, 51, 36, 33, 17, 55, 16, 13, 79, 96, 75, 0]
系统方法排序后:	[0, 13, 16, 17, 24, 33, 36, 49, 51, 55, 70, 75, 79, 88, 96]
希尔方法排序后:	[0, 13, 16, 17, 24, 33, 36, 49, 51, 55, 70, 75, 79, 88, 96]

如果对你有帮助,点个赞,或者打个赏吧,嘿嘿
整理不易,请尊重博主的劳动成果
















以上是关于希尔排序的主要内容,如果未能解决你的问题,请参考以下文章

希尔排序

插入排序(直接插入排序折半插入排序希尔排序的算法思想及代码实现)

希尔排序图解与代码

算法-java代码实现希尔排序

希尔排序JAVA代码

《算法》笔记 3 - 选择排序插入排序希尔排序