面试必备排序算法 - 希尔排序

本贴最后更新于 1064 天前,其中的信息可能已经水流花落

希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由希尔 1959 年公布。希尔排序(Shell's Sort)是插入排序的一种又称"缩小增量排序",是直接插入排序算法的一种高效的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方案的:

  1. 插入排序在对几乎已经排好序的数据操作时,效率高,可以达到线性排序的效率。
  2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

算法原理

算法先将要排序的一组数字按某个增量d分成若干个组,每组中记录的下标相差d。对所有的组进行排序,然后再用一个较小的增量对它进行分组,在每组中再进行排序。直到增量减少到1时,整个排序的数被分成一组,排序完成。

一般初次取序列的一半为增量,以后每次减半,直到增量为1.

给定实例的希尔排序过程如下:

假设待排序列表有10个记录,分别是:

[49, 38, 65, 97, 76, 13, 27, 49, 55, 04]

增量序列的取值依次为:

5,2,1

排序过程图如下:

image.png

代码实现

def shell_sort(ls):
    """
    希尔排序
    :param ls:
    :return:
    """
    n = len(ls)  # 数组长度
    d = n // 2  # 初始增量为数组长度的一半

    while d > 0:
        # 插入排序
        for i in range(d, n):
            cur_index = i  # 当前索引
            pre_index = i - d  # 前一个待比较索引
            while pre_index >= 0:
                if ls[cur_index] < ls[pre_index]:  # 如果当前元素小于前一个元素
                    # 交换
                    ls[cur_index], ls[pre_index] = ls[pre_index], ls[cur_index]
                    # 更换当前索引
                    cur_index = pre_index
                    # 计算下一个待比较的索引
                    pre_index -= d
                else:
                    break
        # 增量除以2
        d = d//2

分析总结

1. 时间复杂度

本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当n值很大时数据项每一趟排序需要移动的个数很少,但数据项的距离很长。当n值减小时每一趟需要移动的数据增多,此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比插入排序高很多。希尔排序的时间的时间复杂度为O(image.png),希尔排序时间复杂度的下界是n*log2n。

2. 空间复杂度

在希尔排序算法过程中,临时占用存储空间大小不变,空复杂度为O(1)

3. 稳定性分析

由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入过程中,相同元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

4.应用分析

希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(image.png)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法.

2 操作
877649301 在 2021-06-02 14:17:39 更新了该帖
877649301 在 2021-06-02 14:02:54 更新了该帖
回帖
请输入回帖内容 ...