算法 — Python递归实现归并排序

1.归并排序原理:将一个序列从中间分成两个子序列,一直分下去,直到子序列中只有一个元素时,停止分裂,开始进行合并。合并时,从只有一个元素的子序列排序后,合并回分裂前的父序列结构,然后再同逻辑合并,直至合并到原序列的结构。其中排序操作需要用到两个下标变量来对比元素,还需要一个新的空序列来接收排序后的序列。原理图如下。

重点是,要先分裂到子序列只有一个元素,才开始合并,所以分裂和合并是分开进行的,分裂为同样的逻辑,且逻辑简单,所以我们可以用递归来进行分裂,用两个变量来接收,然后在下面在进行排序合并操作。

2.分裂步骤:先取出序列长度,再找出序列中间元素的下标(mid),然后用 left(中间左边的子序列) right(中间元素右边的子序列) 来接收递归的返回序列当子序列元素个数为一时则递归返回。
def merge_sort(list1):
    n = len(list1)
    '''递归返回条件,当子列表长度等于1,就可以返回,开始比较 排序 合并'''
    if n <= 1:
        return list1
    mid = n // 2
    left = merge_sort(list1[:mid]) #递归
    right = merge_sort(list1[mid:]) #递归
2.合并步骤: 返回子序列后,就在下面对子序列进行排序和合并。
    L_p,R_p = 0,0
    '''两个变量用来记录子列表的下标'''
    new_list = [] 
    '''新列表用来接收排序后的列表'''
    while (R_p <= len(right)-1) & (L_p <= len(left)-1): #错误案例 R_p <= (len(right)-1) & L_p <= (len(left)-1)
        '''任意一个下标超出了子列表的长度,就停止循环'''
        if right[R_p] < left[L_p]:
            new_list.append(right[R_p])
            R_p += 1
        else:
            new_list.append(left[L_p])
            L_p += 1
    new_list += left[L_p:]
    new_list += right[R_p:]
    '''递归结束后返回新列表''' 
    return new_list

 L_p和R_p为两个下标变量,分别代表着左边子序列和右边子序列的下标,new_list就为新建序列,来接收排序后的列表。排序的逻辑,比如说我们有两个子序列(L和R,假设各自三个元素),L第一个元素和R第一个元素比较,如果L[L_p]小就把L[L_p]尾插进( append() )新序列,然后让L_p后移一位,否则就把R[R_p]尾插进新序列。就这样依次比较下去,直到有一个子序列的下标变量后移出了子序列的范围,就停止排序的循环,然后把另一个序列剩下的元素直接放到新序列的后面。最后的递归出口即 return new_list。返回排序后的序列

调试代码:

import random
a = [random.randint(1,100) for i in range (10)]
print(a)
b = merge_sort(a)
print(b)

返回值:

F:\测试>python -u "f:\测试\数据结构和算法\归并排序.py"
[29, 7, 70, 42, 90, 3, 87, 8, 30, 5]
[3, 5, 7, 8, 29, 30, 42, 70, 87, 90]

3.时间复杂度: O(n*logn),其中分裂的步骤复杂度为O(1),而排序合并的步骤复杂度为O(logn),  递归返回的复杂度为O(n),   而排序合并O(logn)被包含在递归返回后的代码内,所以两者为相乘关系,则复杂度为O(n*logn)。可见归并排序时间复杂度较低,但是我们创建了一个新序列来接收排序后的序列,所以空间复杂度相较于在原序列上修改的排序方法更大了。

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值