通俗易懂-对于归并排序的细节理解python

首先归并排序的原理就是将一个待排序的列表分成二等份,四等份,八等份。。。。直到每一份只有一个元素的时候,然后合并,合并的时候进行排序。听起来有点绕。。。不多说 上代码

def mergesort(alist):
    print('spliting',alist)
    if len(alist)>1:
        mid = len(alist)>>1
        left = alist[:mid]
        right = alist[mid:]
        mergesort(left)
        mergesort(right)

        i,j,k = 0,0,0
        while i<len(left) and j<len(right):

            if left[i]<right[j]:
                alist[k] = left[i]
                i+=1
            else:
                alist[k] = right[j]
                j+=1
            k+=1
        while i<len(left):
            alist[k] = left[i]
            k+=1
            i+=1
        while j<len(right):
            alist[k] = right[j]
            k+=1
            j+=1
    print('merge',alist)

切分其实挺好理解的,从代码中看就是下面这段代码,先找到中点,然后将这段列表分成left和right两部分

mid = len(alist)//2
left = alist[:mid]
right = alist[mid:]
mergesort(left)
mergesort(right)

但是合并怎么理解呢,我们可以举个栗子运行一下这段归并排序的代码,看看结果如何,可以利用代码中的两个print输出看清楚他们是怎么归并的。

result = [12,34,11,5,31]
mergesort(result)
print(result)

这是我用于测试mergesort函数的例子,然后我们看看输出了什么。

spliting [12, 34, 11, 5, 31]
spliting [12, 34]
spliting [12]
merge [12]
spliting [34]
merge [34]
merge [12, 34]
spliting [11, 5, 31]
spliting [11]
merge [11]
spliting [5, 31]
spliting [5]
merge [5]
spliting [31]
merge [31]

我只截了一部分的结果,这部分结果说明的是切分的可视化
从图中可以看到归并排序是将一个列表分成了[12, 34]和[11, 5, 31],然后将[12, 34]分成[12]和[34],[11, 5, 31]分成[11]和[5,31],再将[5,31]分成[5],[31]。这样子就是将一个列表完完全全切分了。然后关键是怎么合并的呢?
下面就是合并的代码

i,j,k = 0,0,0
while i<len(left) and j<len(right):

    if left[i]<right[j]:
        alist[k] = left[i]
        i+=1
    else:
        alist[k] = right[j]
        j+=1
    k+=1
while i<len(left):
    alist[k] = left[i]
    k+=1
    i+=1
while j<len(right):
    alist[k] = right[j]
    k+=1
    j+=1

这段代码其实很简单 就是比较left列表的元素和right列表的元素谁小,小的就装入alist列表中。如果left或者right列表其中一个被装没了(说明先装完的列表小的元素比较多,都装进了alist),那么剩下的left或者right列表就依次全部装入alist(剩下的left或者right列表一定是有序的,下面马上讲原因)。
下面来看看合并结果的可视化:

spliting [12, 34, 11, 5, 31]
spliting [12, 34]
spliting [12]
merge [12]
spliting [34]
merge [34]
merge [12, 34]   #A

A处解释:在这里已经可以看到12和34已经合并了 虽然他们本来就是有序的。

再看11, 5, 31的合并

spliting [11, 5, 31]
spliting [11]
merge [11]
spliting [5, 31]
spliting [5]
merge [5]
spliting [31]
merge [31]
merge [5, 31]#B
merge [5, 11, 31]#C

B处解释:这里合并了5和31 虽然他们也原本就是有序的
C处解释:这里合并了[11],[5,31]这两个列表,利用的就是上面合并的那段代码,谁小谁到alist里边去,注意alist的角色在转换,在一个mergesort代里边alist是代表一段已经拍好序的列表,但是回溯到上一个mergesort代里边,此时的alist可能就变成了上一代mergesort的left或者right,比如这一代是[12,34],下一代就是[12],[34],此时[12]就是left,[34]就是right,合并了的alist就是[12,34],但是回溯到了上一代[12,34]就变成left了,相应的right就变成了排序好的[5,11,31],这就是为什么前面说每一个回溯回来的left都是排序好的,因为此时的left是在下一代中是排序好的alist列表。

C处的解释是归并排序合并的灵魂,如果能看懂的话,应该就深刻理解了归并了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值