面试常考:排序算法(希尔排序)

系列文章
我用一张图彻底理解了冒泡排序
通俗易懂讲解 [图解]选择排序
我去,你竟然还不会插入排序

希尔排序介绍

对于大规模的数组,插入排序很慢,因为它只能交换相邻的元素,每次只能将逆序数量减少 1。希尔排序的出现就是为了解决插入排序的这种局限性,它通过交换不相邻的元素,每次可以将逆序数量减少大于 1。

希尔排序使用插入排序对间隔 gap 的序列进行排序。通过不断减小 gap,最后令 gap=1,就可以使得整个数组是有序的。

下面以数列{80,30,60,40,20,10,50,70}为例,演示它的希尔排序过程。

第1趟:(gap=4)
在这里插入图片描述
当gap=4时,意味着将数列分为4个组: {80,20},{30,10},{60,50},{40,70}。 对应数列: {80,30,60,40,20,10,50,70}

对这4个组分别进行排序,排序结果: {20,80},{10,30},{50,60},{40,70}。 对应数列: {20,10,50,40,80,30,60,70}

第2趟:(n=2)
在这里插入图片描述
当gap=2时,意味着将数列分为2个组:{20,50,80,60}, {10,40,30,70}。 对应数列: {20,10,50,40,80,30,60,70}
注意:{20,50,80,60}实际上有两个有序的数列{20,80}和{50,60}组成。
{10,40,30,70}实际上有两个有序的数列{10,30}和{40,70}组成。
对这2个组分别进行排序,排序结果:{20,50,60,80}, {10,30,40,70}。 对应数列: {20,10,50,30,60,40,80,70}

在这里插入图片描述
在上面的希尔排序中,首先要选取步长gap的值。选取了gap之后,就将数列分成了gap个组,对于每一个组都执行直接插入排序。在排序完所有的组之后,将gap的值减半;继续对数列进行分组,然后进行排序。重复这样的操作,直到gap<0为止。此时,数列也就是有序的了。

约定

待排序的元素需要实现 Java 的 Comparable 接口,该接口有 compareTo() 方法,可以用它来判断两个元素的大小关系。

使用辅助函数 less() 和 swap() 来进行比较和交换的操作,使得代码的可读性和可移植性更好。

排序算法的成本模型是比较和交换的次数。

package 算法.排序;/*
作者     :XiangLin
创建时间 :15/05/2020 17:17
文件     :Sort.java
IDE      :IntelliJ IDEA
*/

public abstract class Sort<T extends Comparable<T>>{
    public abstract void sort(T[] nums);

    protected boolean less(T v, T w){
        return v.compareTo(w) < 0;
    }

    protected void swap(T[] a,int i ,int j){
        T t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

代码

package 算法.排序;/*
作者     :XiangLin
创建时间 :23/05/2020 22:18
文件     :Shell.java
IDE      :IntelliJ IDEA
*/

public class Shell  <T extends Comparable<T>> extends Sort<T> {
    @Override
    public void sort(T[] nums) {
        int N = nums.length;
        int gap = 1;

        while (gap < N / 3){
            gap = 3 * gap + 1;
        }
        while (gap >= 1){
            for (int i = gap;i < N ; i ++){
                for (int j = i;j >= gap && less(nums[j],nums[j - gap]);j -= gap){
                    swap(nums,j,j-gap);
                }
            }
            gap = gap/ 3;
        }
    }
    public static void main(String[] args) {
        Integer[] nums = {52,63,14,59,68,35,8,67,45,99};
        System.out.println("原数组:");
        for(int i :nums){
            System.out.print(i+" ");
        }
        System.out.println();
        Shell s = new Shell();
        s.sort(nums);

        System.out.println("排序后:");
        for(int i :nums){
            System.out.print(i+" ");
        }
    }
}

在这里插入图片描述

总结

本文介绍了希尔排序的基本思想及其代码实现,希尔排序中对于增量序列的选择十分重要,直接影响到希尔排序的性能。我们上面选择的增量序列{n/2,(n/2)/2…1}(希尔增量),其最坏时间复杂度依然为O(n2),一些经过优化的增量序列如Hibbard经过复杂证明可使得最坏时间复杂度为O(n3/2)。希尔排序的介绍到此为止,关于其他排序算法的介绍也会陆续更新,谢谢支持。

另外博主收藏这些年来看过或者听过的一些不错的常用的上千本书籍,没准你想找的书就在这里呢,包含了互联网行业大多数书籍和面试经验题目等等。有人工智能系列(常用深度学习框架TensorFlow、pytorch、keras。NLP、机器学习,深度学习等等),大数据系列(Spark,Hadoop,Scala,kafka等),程序员必修系列(C、C++、java、数据结构、linux,设计模式、数据库等等)以下是部分截图
在这里插入图片描述

更多文章见本原创微信公众号「五角钱的程序员」,我们一起成长,一起学习。一直纯真着,善良着,温情地热爱生活。关注回复【电子书】即可领取哦

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章