[数据结构与算法]-排序算法之希尔排序(shell sort)及其实现(Java)

版权声明:本文为博主原创文章,转载时请注明出处,谢谢!喝酒不骑马 邮箱[email protected] https://blog.csdn.net/Colton_Null/article/details/80878909

本文欢迎转载,转载前请联系作者。若未经允许转载,转载时请注明出处,谢谢! http://blog.csdn.net/colton_null 作者:喝酒不骑马 Colton_Null from CSDN


一.什么是希尔排序?

希尔排序(Shellsort)可以是说是简单排序的一种改进版本(有关插入排序可见我的另一篇博文排序算法之插入排序(insertion sort)及其实现(Java)),它也被称作为缩小增量排序。

希尔排序的发明者是Donald Shell,于1959年提出。该算法是冲破二次时间屏障(O(N²))的第一批算法之一(不过直到它被发现的若干年后才证明了它的亚二次时间界)。它通过比较相距一定间隔的元素来工作;各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止。

插入排序是将相邻元素一次又一次比较、移动、插入,复杂度为O(N²);而希尔排序是通过增量,将数组划分为多个组,对每个组内进行排序。然后不断缩小增量,直到最后增量为1,即相邻元素进行排序。通过这种方式, 使得数组从一开始从大体上看是有序的,小的元素基本在前面,大的元素基本在后面。通过缩小增量,逐步进行局部的微调,最后使整个数组有序。这样,整体的排序效率与简单插入排序相比有所提高。

二.希尔排序的举例实践

对于数组[46, 34, 32, 12, 14, 9, 88, 61]进行排序。

这里我们使用希尔增量进行排序。这里我们使用希尔增量进行排序。希尔增量序列的递推公式如下图。
这里写图片描述

  • 第一次排序,增量gap = 8 / 2 = 4。数组被分为5组,分别为[46, 14], [34, 9], [32, 88], [12, 61]
    排序后的数组为[14, 9, 32, 12, 46, 34, 88, 61]

  • 第二次排序,增量gap = 4 / 2 = 2。数组被分为2组,分别为[14, 32, 46, 88], [9, 12, 34, 61]
    排序后的数组为[14, 9, 32, 12, 46, 34, 88, 61]

  • 第三次排序,增量gap = 2 / 2 = 1。直接对数组[14, 9, 32, 12, 46, 34, 88, 61]进行插入排序。
    排序后的数组为[9, 12, 14, 32, 34, 46, 61, 88]

三.代码实现

ShellSort.java

public class ShellSort {

    /**
     * shellsort 希尔排序
     *
     * @param arr 被排序的数组
     * @param <T>
     */
    public static <T extends Comparable<? super T>> void shellSort(T[] arr) {
        int p;
        // 增量gap,并逐步减半
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            // 从第gap个元素,对其所在的组进行直接插入排序操作
            for (int i = gap; i < arr.length; i++) {
                T tmp = arr[i];
                // 同插入排序,进行移位
                for (p = i; p >= gap && tmp.compareTo(arr[p - gap]) < 0; p -= gap) {
                    arr[p] = arr[p - gap];
                }
                arr[p] = tmp;
            }
        }
    }
}

ShellSortTest.java 测试类

public class ShellSortTest {
    public static void main(String[] args) {
        Integer[] arr = {46, 34, 32, 12, 14, 9};
        ShellSort.shellSort(arr);
        print(arr);
    }


    private static <T> void print(T[] arr) {
        for (T t : arr) {
            System.out.print(t.toString() + " ");
        }
        System.out.println();
    }
}

输出:9 12 14 32 34 46

四.有关希尔排序的复杂度分析

希尔排序的代码实现虽然简单,但是有关它的复杂度分析可没这么容易。希尔排序的算法复杂度与增量序列的选择密不可分。这里列出常见的两个增量序列的时间复杂度结果。有关其证明在本博客中也不做相关证明了,有兴趣的朋友可以自行搜索一下相关材料。有时间的话我会把有关希尔排序时间复杂度的证明更新上来。

  1. 希尔增量的时间复杂度。
    最坏的情况复杂度为O(N²)

  2. Hibbard增量的时间复杂度:
    最坏的情况事件负责为O(N 3 / 2 )


有关[数据结构与算法]的学习内容已经上传到github,喜欢的朋友可以支持一下。 https://github.com/MaYuzhe/data-structures-and-algorithm-study-notes-java


站在前人的肩膀上前行,感谢以下博客及文献的支持。

猜你喜欢

转载自blog.csdn.net/Colton_Null/article/details/80878909