美文网首页收藏算法入门教程
05《算法入门教程》希尔排序

05《算法入门教程》希尔排序

作者: 木子教程 | 来源:发表于2022-05-03 10:24 被阅读0次

    1. 前言

    本节内容是排序算法系列之一:希尔排序,主要讲解了希尔排序的主体思路,选取了一个待排序的数字列表对希尔排序算法进行了演示,给出了希尔排序算法的 Java 代码实现,帮助大家可以更好的理解希尔排序算法。

    2. 什么是希尔排序?

    希尔排序(Shell Sort),是计算机科学与技术领域中较为简单的一种排序算法。

    希尔排序是插入排序的一种,有时候也被称为 “缩小增量排序”。它是插入排序的改进版,与插入排序的不同之处在于,希尔排序会优先比较距离较远的元素。希尔排序是按照其设计者希尔(Donald Shell)的名字命名而来,并于 1959 年公布出来。

    3. 希尔排序过程

    在介绍完希尔排序之后,我们一起来看一下希尔排序的实现步骤具体是什么样的吧。这里我们假设待排序的序列为 [9,2,11,7,12,5],我们按照从小到大的序列进行排序。

    3.1 算法步骤

    1. 步骤 1:

    选择一个增量序列 k1,k2, … km,其中 k1>k2>…km=1,即增量序列大小依次减小,并且最后一个增量序列大小为 1。

    1. 步骤 2:

    按照增量序列的个数 m,对整个待排序序列进行 m 趟排序。

    1. 步骤 3:

    每一趟排序,根据对应的增量 ki,需要将待排序的序列分成对应长度的子序列,分别在子序列上面进行直接插入排序。当且仅当增量序列为 1 时,整个序列作为一个整体处理。

    其实,上面的步骤 1步骤 2 都是在排序之前进行的处理,选择对应的增量。上面的 步骤 3 每执行一次,就相当于是进行了一次插入排序,只是每次都会选择一个增量,将整个待排序序列按照增量进行划分,然后在对应增量上面进行插入排序。接下来,让我们用上面的待排序数字队列 [9,2,11,7,12,5] 进行整个算法步骤的排序演示工作。

    3.2 算法演示

    按照 2.1 节的排序步骤,我们需要先选择对应的希尔排序中的增量值,按照一般性的原则,我们可以将增量按照待排序的序列长度依次整除 2,直到增量为 1 停止,得到对应的增量。如下:

    6/2 = 3, 3/2 = 1    //依次获得增量值3,1,除法取整
    
    

    接着,我们调用 2.1 中的步骤 2, 步骤 3,按照增量值的取法,依次进行对应序列的插入排序,首先我们取增量值为 3,对应排序示例如下:

    [9,2,11,7,12,5]   -->  [9,7],[2,12],[11,5]   //增量取3,整个待排序序列按照增量为3进行分组,分成3组,依次排序
    [9,7],[2,12],[11,5] -->  [7,9],[2,12],[5,11]   //对应增量位置进行排序
    [7,9],[2,12],[5,11] -->  [7,2,5,9,12,11]   //完成第一次的对应增量的排序过程
    
    

    Tips: 希尔排序过程中会每次选择一个增量值,然后将待排序列表按照增量值进行分组,对应的分组内部进行插入排序。

    在完成增量为 3 的插入排序之后,我们接着进行增量为 1 的插入排序,这个步骤其实跟我们之前的插入排序步骤完全一致。整个过程如下:

    [7,2,5,9,12,11]     -->  [7];[2,5,9,12,11]   //插入排序初始化,选择第一个元素作为排序好的序列
    [7];[2,5,9,12,11]   -->  [2,7];[5,9,12,11]   //选择未排序元素2,插入排序好的序列[7]形成新的排序好序列[2,7]
    [2,7];[5,9,12,11]   -->  [2,5,7];[9,12,11]   //选择未排序元素5,插入排序好的序列[2,7]形成新的排序好序列[2,5,7]
    [2,5,7];[9,12,11]   -->  [2,5,7,9];[12,11]   //选择未排序元素9,插入排序好的序列[2,5,7]形成新的排序好序列[2,5,7,9]
    [2,5,7,9];[12,11]   -->  [2,5,7,9,12];[11]   //选择未排序元素12,插入排序好的序列[2,5,7,9]形成新的排序好序列[2,5,7,9,12]
    [2,5,7,9,12];[11]  -->  [2,5,7,9,11,12]   //选择未排序元素11,插入排序好的序列[2,5,7,9,12]形成新的排序好序列[2,5,7,9,11,12]
    
    

    Tips: 增量为 1 时候执行 步骤 3,实际上就是执行一次插入排序,只是在执行插入排序之前,之前的序列在一定程度上面已经进行了插入排序,所以在增量为 1 的插入排序过程中可以减少插入时候比较的次数,从而可以在一定程度上面减少算法的运行时间。

    从上面的示例可以看出,其实整个希尔排序的过程,就是根据增量大小依次进行插入排序,本质上还是针对插入排序的一种优化。

    4. Java 代码实现

    在说明希尔排序的整个过程之后,接下来,我们看看如何用 Java 代码实现希尔排序算法。

    import java.util.Arrays;
    
    public class ShellSort {
    
        public static void main(String[] args) {
    
            //初始化需要排序的数组
            int array[] = {9, 2, 11, 7, 12, 5};
            //初始化希尔排序的增量为数组长度
            int gap = array.length;
            //不断地进行插入排序,直至增量为1
            while (true) {
                //增量每次减半
                gap = gap/2;
                for (int i = 0; i < gap; i++) {
                    //内部循环是一个插入排序
                    for (int j = i + gap; j < array.length; j += gap) {
                        int temp = array[j];
                        int k = j - gap;
                        while (k >= 0 && array[k] > temp) {
                            array[k + gap] = array[k];
                            k -= gap;
                        }
                        array[k + gap] = temp;
                    }
                }
                //增量为1之后,希尔排序结束,退出循环
                if (gap == 1)
                    break;
            }
            //打印出排序好的序列
            System.out.println(Arrays.toString(array));
        }
    
    }
    
    

    运行结果如下:

    [2, 5, 7, 9, 11, 12]
    
    

    代码中的第 8 行初始化一个需要排序的数组,后面按照从小到大的排序规则,实现了数组的排序。第 12 行至 30 行是整个希尔排序的流程。第 14 行代码表示希尔排序中的增量每次整除 2 取得,第 17 行至 25 行是一个 for 循环结构,表明按照增量进行插入排序。最后第 32 行代码输出排序好的数组。

    5. 小结

    本节主要学习了希尔排序算法,通过本节课程的学习,需要熟悉希尔排序的算法流程,知道希尔排序算法的实现思路,可以自己用代码实现希尔排序算法。至此,我们已经学习了排序算法中的冒泡排序、插入排序、选择排序、希尔排序。

    相关文章

      网友评论

        本文标题:05《算法入门教程》希尔排序

        本文链接:https://www.haomeiwen.com/subject/evmbyrtx.html