Swift算法-希尔排序Shell Sort

声明:算法和数据结构的文章均是作者从github上翻译过来,为方便大家阅读。如果英语阅读能力强的朋友,可以直接到swift算法俱乐部查看所有原文,以便快速学习。作者同时也在学习中,欢迎交流

希尔排序是基于插值排序的算法,通过将原始数据分为总数更小的几个小数组,并在这些小数组中整理排序的方式来提升插值排序的性能。

这里有一个模仿希尔算法执行过程的表演-匈牙利某大学传统舞蹈小视屏

执行原理

与插值排序通过对比相邻的两个元素的大小并在必要时候交换位置,希尔排序是通过比较相隔很远的两个元素。

两个元素之间的距离称为间隔。如果两个元素在比较之后需要交换位置,则直接更换彼此的位置。这个过程减少了插值排序中很多不必要的中间复制过程,即从两个元素更换位置前需要不断交换相邻元素的位置直到目的位置。
这里的最主要的思想就是,元素通过每次移动较大间隔,整个数组可以快速形成局部排序好的情况。这个会让接下来的交换变得更加快速。因为元素之间不需要进行过多次的位置交换。

一旦某一距离长度的间隔比值交换完成,间隔会变得越来越小,然后进行相应间隔的比值交换,这样的过程不断重复,直到间隔为1,也就是与插值排序同样过程的情况。然而,在希尔排序中,由于大部分数据在此时已经整理完毕,所以最后间隔为1的比值交换速度非常快。

例子

假设我们要用希尔排序对数组[64, 20, 50, 33, 72, 10, 23, -1, 4]进行整理。
我们从间隔为数组长度二分一开始:

n = floor(9/2) = 4

我们创建n个子数组。在每一个数组中,不同元素之间的间隔距离为n。在我们的例子中中,我们需要创建4个这样的数组。这些数据会通过insertionSort()函数进行整理排序。我们可以通过图表进行深入了解:

sublist 0:  [ 64, xx, xx, xx, 72, xx, xx, xx, 4  ]
sublist 1:  [ xx, 20, xx, xx, xx, 10, xx, xx, xx ]
sublist 2:  [ xx, xx, 50, xx, xx, xx, 23, xx, xx ]
sublist 3:  [ xx, xx, xx, 33, xx, xx, xx, -1, xx ]

如图所示,每一个子数组里面只包含原数组中每一个第4个元素。其他非第4元素的用xx表示。所以第一个子数组为[64,72,4],第二个为[20,10],以此类推。这里我们使用间隔的原因是我们不需要直接创建新的数组,所有的交换过程都在原始数组中完成。

现在我们开始使用insertionSort()函数进行每个子数组的整理排序。比如第一个子数组中,我们需要先将4和72交换位置,然后是4和64,然后72大于64不需要交换。整理后的第一个子数组为:
sublist 0: [ 4, xx, xx, xx, 64, xx, xx, xx, 72 ]
其他子数组也完成同样过程,得到结果如下:

sublist 1:  [ xx, 10, xx, xx, xx, 20, xx, xx, xx ]
sublist 2:  [ xx, xx, 23, xx, xx, xx, 50, xx, xx ]
sublist 3:  [ xx, xx, xx, -1, xx, xx, xx, 33, xx ]

此时,从原数组中看,结果是这样的:
[ 4, 10, 23, -1, 64, 20, 50, 33, 72 ]
现阶段并不是完全整理好的,但是对比最早时候的数据,已经相对有序的多。现在第一次比值交换结束,我们开始进行第二次交换。将第一次的交换间隔除以2,得到第二次间隔2.
n = floor(4/2) = 2
这也意味着我们这次只需要创建两个子数组。

sublist 0:  [  4, xx, 23, xx, 64, xx, 50, xx, 72 ]
sublist 1:  [ xx, 10, xx, -1, xx, 20, xx, 33, xx ]

每个子数组包含间隔2的元素。重复之前的步骤,我们继续使用insertionSort()函数进行每个子数组的整理排序。结果如下:

sublist 0:  [  4, xx, 23, xx, 50, xx, 64, xx, 72 ]
sublist 1:  [ xx, -1, xx, 10, xx, 20, xx, 33, xx ]

通过观察我们可以发现,每一个子数组中均只有2个元素不在正确的位置上,所以在这一次的插值排序速度很快。

此时的原始数组为:
[ 4, -1, 23, 10, 50, 20, 64, 33, 72 ]
到这里第二次比值交换也结束,我们只需要进行最后一次比值交换,间隔为1:
n = floor(2/2) = 1
这也意味着这次的子数组个数为1,可以直接对当前的数组进行整理,继续使用insertionSort()函数。结果如下:
[ -1, 4, 10, 20, 23, 33, 50, 64, 72 ]
对希尔排序算法来说,大部分情况下它的性能是O(n^2),当然运气好的时候是 O(n log n)。需要注意的是,希尔排序算法得到的是不稳定序列,它可能会对数值相同的两个元素进行位置交换。

间隔序列

间隔序列决定了间隔的初始值以及每次迭代过程中新的间隔值。对于希尔排序算法来说,一个好的间隔序列可以让整个算法表现的更好。

间隔序列的取值方法不是唯一的,在我们文中,我们采用的是整理数组个数的二分一,然后每次迭代继续除以二分一的策略。

代码

var arr = [64, 20, 50, 33, 72, 10, 23, -1, 4, 5]

public func shellSort(_ list: inout [Int]) {
    
    var sublistCount = list.count / 2
   
    while sublistCount > 0 {
        
        for index in 0..<list.count {
           
            guard index + sublistCount < list.count else { break }
            
            if list[index] > list[index + sublistCount] {
                swap(&list[index], &list[index + sublistCount])
            }
            
            guard sublistCount == 1 && index > 0 else { continue }
            
            if list[index - 1] > list[index] {
                swap(&list[index - 1], &list[index])
            }
        }
        sublistCount = sublistCount / 2
    }
}

shellSort(&arr)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容

  • 排序的基本概念 在计算机程序开发过程中,经常需要一组数据元素(或记录)按某个关键字进行排序,排序完成的序列可用于快...
    Jack921阅读 1,361评论 1 4
  • 该系列文章主要是记录下自己暑假这段时间的学习笔记,暑期也在实习,抽空学了很多,每个方面的知识我都会另起一篇博客去记...
    Yanci516阅读 12,067评论 6 19
  • 排序算法说明 (1)排序的定义:对一序列对象根据某个关键字进行排序; 输入:n个数:a1,a2,a3,…,an输出...
    BULL_DEBUG阅读 722评论 0 3
  • 数据结构与算法--排序之冒泡、选择、插入、希尔 我们关注的主要对象是重新排列数组元素的算法,每个元素都有一个主键,...
    sunhaiyu阅读 1,079评论 2 12
  • 用刷微博的时间来总结今日应该有多好,每日精进。 完成了Excel表格,计算机二级真的很恶心,没有报班学习一头雾水但...
    六夏妹儿阅读 146评论 0 0