希尔排序 | 通俗易懂的理解排序过程

懵懂的女人 提交于 2019-11-29 06:43:48

响应群众需求,今天安排上「希尔排序」。

阅读本文前,请先服用「插入排序」,效果更加。

Content

  • 实现过程
  • 关键思路
  • 代码实现
  • 结合代码和中间过程,再体会
  • 算法评价
  • 「希尔排序」🆚 「插入排序」
  • 听说有彩蛋❓

👀「更多排序
冒泡排序 | 通俗易懂的理解排序过程
选择排序 | 通俗易懂的理解排序过程
快速排序 | 通俗易懂的理解排序过程
插入排序 | 通俗易懂的理解排序过程


1. 实现过程

[5,4,1,3,2]升序排列,中间步骤 ⬇️
在这里插入图片描述


2. 关键思路

「希尔排序」—— 按固定间隔划分子序列,对每个子序列实现简单插入排序。

这么来看,「希尔排序」可以拆解成两大步骤

  1. 划分子序列;
  2. 在子序列中简单插入排序。

Q:怎么划分子序列?

  • 等间隔划分。本例中,初始下标之差按照d= n//2计算,之后 d = d//2 循环更新。
  • 先做远距离的移动,再逐渐缩小间隔。这样,可以减少移动的次数,因为极端情况,间隔为1时即退化为简单插入排序。

Q:简单插入排序怎么操作?

  • 简单概括 —— 比较、后移、腾位置、插入target。没看过简单插入排序的,点这里。

3. 代码实现

def ShellSort(arr):
    
    def ssort(arr, d):
        n = len(arr)
        for i in range(d, n):
            j = i-d  # 被比较数下标
            target = arr[i]  # target
            while j>=0 and arr[j] > target:  # 比较、后移、腾位置
                arr[j+d] = arr[j]
                j -= d
            if j != i-d:
                arr[j+d] = target  # 插入
    
    n = len(arr)
    if n <= 1:
        return arr
    d = n//2  # 子序列的初始下标之差
    while d >= 1:
        ssort(arr, d)
        d = d//2  # 循环更新
    return arr

4. 结合代码和中间过程,再体会

在这里插入图片描述在这里插入图片描述


5. 评价

  • 算法是不稳定的,因为跳跃性插入;
  • 平均时间复杂度 O(nlogn);(不理解,待解释~)
  • 额外空间开销出在插入过程数据移动需要的一个暂存,空间复杂度O(1)。

6. 「希尔排序」🆚 「简单插入排序」

  • 联系

「希尔排序」在划分子序列后,对每个子序列实现简单插入排序

  • 区别

「希尔排序」优化了「简单插入排序」,移动次数更少。

同样以 [5,4,1,3,2]升序排列为例,「简单插入排序」中共移动了8次,「希尔排序」中共移动了4次。

Q:移动次数,节省再哪里了?效率是如何提高的呢?

Example

[5,4,1,3,2] 调整成 [1,4,5,3,2], 两者的中间过程是如何的?(过程截图于完整的实现过程)

因为是挨个比较、移动、腾位置,每次插入都要移动大量数据

  • 「希尔排序」
    在这里插入图片描述

因为实现了跨越的(等间隔)的比较、移动、腾位置,可以一步到位

不过,如果序列基本有序,简单插入排序就不必做很多移动操作,此时效率还是很高的。所以,「希尔排序」先做远距离移动使序列基本有序,再不断缩小划分间隔,直至最后为间隔为1时的简单插入排序。


7. Good things will come ~

在这里插入图片描述
你不知道收到这张卡片的我当时内心翻腾得有多厉害,暖流从心底涌上,直接泪崩。

我和舍友把它贴在门后,每每需要力量的时候,就再读一遍,'Good things will come’ 是我们所有的信念

想起一句话 —— 「所有的事情最后都会是好事,如果现在没有,说明还没到最后」。

最后,在哪儿呢?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!