排序算法专题-归并排序

  归并排序是一种十分经典的冲破O(n2)时间复杂度的排序算法,该算法是基于分治的思想,讲解算法原理之前,先看一下下面这张图。
在这里插入图片描述

  • 图片来源:【算法】排序算法之归并排序
      上图就是归并算法的一个简单示例。该算法就是每次将数组递归拆解为两部分,直到所有部分包含元素为1,之后递归的将各个部分进行归并。
  • 具体的算法步骤如下:
  • 1:递归拆解数组,直到每个区块包含元素数量为1
    2:归并数组,直到归并后的数组长度等于原数组长度
    3: 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
    4:设定两个指针,最初位置分别为两个已经排序序列的起始位置
    5:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
    5:重复步骤 4直到某一指针达到序列尾
    7:将另一序列剩下的所有元素直接复制到合并序列尾
    8:重复步骤2-7

  从上述可以看出,该算法的实现是基于递归思想,但是所有的递归都可以转换成迭代,因此该算法有两个实现方式,递归和迭代。

  • 代码如下,以递归为例:
  • 如果单从原理原理上来直接写代码会比较复杂,我们可以将该算法拆解为两个部分,及分割和归并。分割是一个简单的递归,代码如下:
def mergeSort(nums):
    """
    将输入数组递归拆分,直到长度为1时返回,对每一步返回的left,right进行顺序归并
    >>>mergeSort(3,38, 5, 44, 15, 36)
    >>>[3, 5, 15, 36, 38, 44]
    """
    if len(nums) < 2:
        return nums
    mid = len(nums)//2
    left, right = nums[:mid], nums[mid:]
    return mergeHelp(mergeSort(left), mergeSort(right))
  • 其中mergeHelp是mergeSort的一个help方法,用于对拆分后的数组进行顺序归并。
  • 以[3,38, 5, 44, 15, 36]举个栗子,说一下递归过程:
  • 1:[3, 38, 5] [44, 15, 36]
    2:[3] [38, 5]
    3:[38] [5]
    4:[44] [15, 36]
    5:[15] [36]

  • 接下来我们实现mergeHelp方法,就是给定两个有序数组,将其按顺序合并为一个数组,代码如下:
def mergeHelp(left, right):
    """
    归并排序的help方法,用于将拆分的left和right进行顺序归并
    >>>mergeHelp([1, 3, 5], [2, 4, 5]):
    >>>[1, 2, 3, 4, 5, 5]
    """
    res = []
    while left and right:
        if left[0] <= right[0]:
            res.append(left.pop(0))
        else:
            res.append(right.pop(0))
    while left:
        res.append(left.pop(0))
    while right:
        res.append(right.pop(0))
    return res
  • 当我们实现了这个方法之后,看一下分割+归并的过程
  • [3, 38, 5] [44, 15, 36]  第一次分割
    左数组[3, 38, 5]部分:
    [3] [38, 5]  第一次分割
    [38] [5]  第二次分割(左数组分割完毕,所有部分元素均为1)
    [5, 38]  第一次归并
    [3, 5, 38]emsp; 第二次归并,完成[3, 38, 5]部分序列的排序
    右数组[44, 15, 36]部分:
    [44] [15, 36]  第一次分割
    [15] [36]  第二次分割
    [15, 36]  第一次合并
    [15, 36, 44]  第二次合并
    原数组的所有子序列完成排序,进行最终的合并
    [3, 5, 15, 36, 38, 44]  排序完成

  • 算法解析:算法的时间复杂度从两个部分来看,很明显在mergeSort()递归方法里面,迭代公式为mid = len(nums)//2,该方法的时间复杂度是O(log n),而在mergeHelp()归并方法里面,每一步像res里面追加一下元素,最终的的运行次数为len(left)+len(right),很明显时间复杂度为O(n),因此归并排序算法的总时间复杂度为O(n log n)。由于算法运行过程中,会递归生成原数组的切片,切片总长度为n,所以归并排序算法的空间复杂度为O(n)。
  • 注意到我们在进行归并操作是,使用的是如下代码
while left and right:
        if left[0] <= right[0]:
            res.append(left.pop(0))
        else:
            res.append(right.pop(0))
  • 也就是说对于同样大小的元素,我们先插入位于左边的,而后插入右边的,因此归并排序不会改变相同元素的相对位置,因此该算法是稳定的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lemon_tttea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值