写给媳妇儿的算法(七)——归并排序

归并排序是一个从思路到实现都极其的像快速排序的一个排序算法。同样,归并排序使用的思想也是 分治 思想,大事化小,小事化了

算法过程

回到我们的那个老问题,什么样的数列是绝对有序的?答案是空数列或者只含有一个数的数列是绝对有序的。归并排序就是先分解再合并,首先把数列通过二分的方式不停的进行分割,直到分割成所有的数列中的数都被拆开(这样没一个分出来的子数列就是绝对有序的),然后两两进行合并组成新的数列,再和其他的用同样方式组成的数列合并……直到最后,整个数列被合并为之前的数量,整个数列就排序完成。

如下图的上半部分,我们将原始数列经过几次的从中间拆分成两部分的操作,最终将数列 拆无可拆 ,变成了数列中所有的数都 “各自为战” ,这些各自为战的每一个数就是一个有序数列(就自己一个,当然是有序的)。

如下图的下半部分,我们将经过第一步拆分成各自为战的各个小的“数列”(单个的数)依次两两进行合并。这个过程就是将 两个有序数列 合并成 一个有序数列 的过程。合并到最后,并无可并 的时候,所有的数此时都被重新排列了,整个数列完成了排序,全部有序!

归并排序先分解再合并过程图.png

拆分的时候,比较容易拆分,我们合并的时候怎么合并呢?合并就是把两个有序数列合并成一个有序数列的过程。这个过程的具体操作如下图所示:

假设下图左侧的上下两个数列就是待合并的两个数列,右侧的数列就是合并之后的效果。右边的效果的合并过程,就如图中曲线中间的标号顺序:

  1. 设左侧上边数列为【1】,下边数列为【2】,右边的数列为合并后的新数列。(注意:【1】、【2】都是有序的)
  2. 比较【1】、【2】的第 1 个位置,2 < 7,因此,将【2】中的第一个数 2 移动到右边的新数列的第 1 个位置,【2】中的第 1 个数找到了归宿。
  3. 把还没有找到归宿的【2】的第 2 个数和【1】的第一个数比较,4 < 7, 因此将【2】中的第 2 个数 4 移动到右边新数列的第 2 个位置,【2】中的第 2 个数找到了归宿。
    ……
  4. 就是这样,【1】【2】中每找到一个数的归宿,就用这个数后面的数拿出来去比较,然后小的数移动到新的数列中。最终我们发现,其中一个数列会被 “搬空” ,就是我们这里的【2】。而【1】中还剩余两个数 10、12 。当出现 “搬空” 的时候,我们就把另外一个没被 “搬空” 的数列剩余的所有的数,原封不动的移动到新的数列的最后去。
  5. 最终我们发现,我们在这样的交叉=>比较=>后移=>比较中,把两个有序数列【1】、【2】合并成了一个新的有序数列。这就是合并两个有序数列为一个有序数列的方法。
合并两个有序数组的过程图.png

最终,通过先拆分,再合并,合并的过程中借助一个两两合并有序数列的方法,我们完成了最终的归并排序的全过程,我们的原始数列被排序完成!

算法实现

#coding:utf-8

import numpy as np 

# 归并排序
def merge_sort(data):
    merge_sort_content(data, 0, len(data)-1)

# 递归进行归并排序的实体部分
def merge_sort_content(data, f, t):
    if f >= t:
        return
    
    center = (f + t) // 2
    merge_sort_content(data, f, center)
    merge_sort_content(data, center+1, t)
    merge(data, f, center, t)

# 合并数组中的两部分
def merge(data, f, c, t):
    i = f
    j = c + 1
    temp = []

    # 把最小的依次放入临时数组中,此处需要额外开辟空间,所以归并排序不是就地排序,需要额外空间
    while i <= c and j <= t:
        if data[i] < data[j]:
            temp.append(data[i])
            i += 1
        else:
            temp.append(data[j])
            j += 1

    # 把没有挪完到临时数组的部分,挪到临时数组
    start = i 
    end = c
    if j <= t:
        start = j 
        end = t
    for k in range(start, end+1): # python的区间是左闭右开
        temp.append(data[k])

    # 把临时数组中的数,都拷贝回排序的区间上去
    data[f:t+1] = temp

array = np.arange(20)
np.random.shuffle(array)
array = list(array)
print('输入的数据: {}'.format(array))
merge_sort(array)
print('排序之后的数据:{}'.format(array))

结果是:

归并排序的结果.png



上一篇:写给媳妇儿的算法(六)——快速排序
下一篇:写个媳妇儿的算法(八)——桶排序

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