归并排序算法的Python实现(头歌教学实践平台)

任务描述

本关任务:编写代码实现归并排序。

相关知识

为了完成本关任务,你需要掌握: 1.如何实现归并排序; 2.归并排序算法的分析。

归并排序

分而治之的策略可以用来改进排序算法,归并排序就是分治策略在排序算法上的典型应用。归并排序是一种递归算法,其算法思路是将列表持续地拆分为两半,再对这两半分别进行归并排序。

图 1 展示了对一个含有 9 个数据项的列表进行归并排序的拆分过程。

图1 归并排序的列表拆分过程

如果列表里的数据项个数超过一个,就把列表拆分,然后再分别对拆分后的两个部分递归进行排序。图 1 中的列表首先被拆分为 [54,26,93,17] 和 [77,31,44,55,20] 左右两部分。然后对左右两部分分别再进行拆分,左部分继续被拆分为 [54,26] 和 [93,17]。[54,26] 再被拆分为 [54] 和 [26],当列表中的数据项只有一个时,就结束这个递归过程。

一旦拆分成的两个部分被排序好,就执行归并操作。图 2 展示了对以上列表进行归并排序时,已拆分的列表被排序好后再被重新归并回去的过程。

 图2 归并排序的列表归并过程

归并的过程是把两个排好序的列表结合在一起,组合成一个单一的、有序的新列表。如图 2 最后一步归并是将已排好序的两个列表 [17,26,54,93] 和 [20,31,44,55,77] 组合成一个新的有序列表。归并的过程首先将第一个列表中最小的 17 和第二个列表中最小的 20 进行比较,17 小于 20,于是将 17 放置在一个新的结果列表中。然后将第一个列表中当前最小的 26 与第二个列表中当前最小的 20 进行比较,26 大于 20,于是将 20 放置在结果列表中。以此类推,直至两个列表的所有数据项都按从小到大的顺序放置在结果列表中。

归并排序的算法实现可总结为以下几个关键点:

  1. 递归的基本结束条件:列表中仅有 1 个数据项时,自然是排好序的;

  2. 缩小规模:将列表拆分为两半,规模减为原来的二分之一;

  3. 调用自身:对分为两半的列表分别调用自身来排序,然后将分别排好序的两半进行归并,得到最终排好序的整个列表。

归并排序的算法分析

我们可以将归并排序分为两个过程来分析:

  • 拆分的过程,借鉴二分查找中的分析结果,是对数复杂度,其时间复杂度为O(logn)

  • 归并的过程,对于拆分的每个部分,其所有数据项都会被比较和放置一次,所以是线性复杂度,其时间复杂度是O(n)

综合考虑,每次拆分的部分都进行一次O(n)的数据项归并,因此总的时间复杂度是O(nlogn)。此外,归并排序算法使用了额外 1 倍的存储空间用于归并,因此空间复杂度为O(n)

编程要求

在右侧编辑器中的 Begin-End 区间补充代码,根据归并排序的算法思想完成mergeSort方法,从而实现对无序表的排序。

测试说明

平台会对你编写的代码进行测试,比对你输出的数值与实际正确的数值,只有所有数据全部计算正确才能通过测试:

测试输入:

  1. 54,26,93,17,77,31,44,55,20

输入说明:输入为需要对其进行排序的无序表。

预期输出:

  1. [17, 20, 26, 31, 44, 54, 55, 77, 93]

输出说明:输出的是对无序表进行归并排序后的结果,以列表的形式展现。

测试输入:

  1. 49,38,65,97,76,13,27

预期输出:

  1. [13, 27, 38, 49, 65, 76, 97]

开始你的任务吧,祝你成功!

'''请在Begin-End之间补充代码, 完成mergeSort函数'''

def mergeSort(alist):
    if len(alist)>1:  # 基本结束条件
        mid = len(alist)//2
        lefthalf = alist[:mid]
        righthalf = alist[mid:]
        # 递归调用mergeSort来对切片得到左半部分和右半部分进行排序
        # ********** Begin ********** #    
        mergeSort(lefthalf)
        mergeSort(righthalf)
        # ********** End ********** #
        i=0
        j=0
        k=0
        # 此时左半部分和右半部分都已排好序,接下来需要对排好序的左右两半进行合并
        while i<len(lefthalf) and j<len(righthalf):
            # 拉链式交错把左右半部分从小到大归并到结果列表中
            if lefthalf[i]<righthalf[j]:
                alist[k]=lefthalf[i]
                i=i+1
            else:
                # ********** Begin ********** #    
                alist[k]=righthalf[j]
                j+=1
                # ********** End ********** #
            k=k+1
        # 归并左半部分的剩余项
        while i<len(lefthalf):
            alist[k]=lefthalf[i]
            i=i+1
            k=k+1
        # 归并右半部分的剩余项
        while j<len(righthalf):
            # ********** Begin ********** #    
            alist[k]=righthalf[j]
            j+=1
            k+=1
            # ********** End ********** #

 


第2关:归并排序的另一个实现

任务描述

本关任务:编写更具 Python 风格的归并排序代码。

相关知识

为了完成本关任务,你需要掌握:Pyhon 列表 List 中的一些方法。

为了让代码更简洁,具有更优异的可读性,可以利用 Python 中列表 List 的方法来实现更具 Python 风格的归并排序代码。

  • list.append():在列表末尾添加新的对象。 该方法的语法为:

  1. list.append(obj) # obj 表示添加到列表末尾的对象

示例如下:

  1. aList = [123, 'x', 'y', 'z']
  2. aList.append(456)
  3. print(aList)

输出:

  1. [123, 'x', 'y', 'z', 456]
  • list.extend():在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)。 该方法的语法为:
  1. list.extend(seq) # seq 表示一个元素列表

示例如下:

  1. aList = [123, 'x', 'y', 'z', 456]
  2. bList = [789, 'a']
  3. aList.extend(bList)
  4. print(aList)

输出:

  1. [123, 'x', 'y', 'z', 456, 789, 'a']
  • list.pop():移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。 该方法的语法为:
  1. list.pop(index=-1) # index 为可选参数,表示要移除列表元素的索引值,默认为删除最后一个列表值

示例如下:

  1. aList = [123, 'x', 'y', 'z', 456]
  2. list_pop=aList.pop(0)
  3. print("删除的项为 :", list_pop)
  4. print("列表现在为 :", aList)

输出:

  1. 删除的项为 : 123
  2. 列表现在为 : ['x', 'y', 'z', 456]

编程要求

根据提示,在右侧编辑器中的 Begin-End 区间补充代码,根据归并排序的算法思想完成merge_sort方法,从而实现对无序表的排序。

测试说明

平台会对你编写的代码进行测试,比对你输出的数值与实际正确的数值,只有所有数据全部计算正确才能通过测试:

测试输入:

  1. 54,26,93,17,77,31,44,55,20

输入说明:输入为需要对其进行排序的无序表。

预期输出:

  1. [17, 20, 26, 31, 44, 54, 55, 77, 93]

输出说明:输出的是对无序表进行归并排序后的结果,以列表的形式展现。

测试输入:

  1. 49,38,65,97,76,13,27

预期输出:

  1. [13, 27, 38, 49, 65, 76, 97]

提示:

  1. i = [1, 2, 3]
  2. j = []
  3. print(i if i else j)

输出:

  1. [1, 2, 3]

开始你的任务吧,祝你成功!

'''请在Begin-End之间补充代码, 完成merge_sort函数'''

# python风格的归并排序
def merge_sort(lst):
    # 递归结束条件
    if len(lst) <= 1:
        return lst
    # 分解问题,并递归调用
    middle = len(lst) // 2
    # 分别对左半部分和右半部分进行归并排序
    # ********** Begin ********** #    
    left=merge_sort(lst[:middle])
    right=merge_sort(lst[middle:])
    # ********** End ********** #
    # 合并左右半部,完成排序
    merged = []
    # 只要左右部分还有数据,就进行合并
    # 将左半部分的首个数据(位置为0的数据)与右半部分的首个数据进行比较
    # 把更小的数据添加到merged列表中,同时把它从原来所在列表中删除(下一次比较还是从0位置开始)
    while left and right:
        if left[0] <= right[0]:
            # ********** Begin ********** #    
            merged.append(left.pop(0))
            # ********** End ********** #
        else:
            merged.append(right.pop(0))
    # 合并未合并的部分
    # ********** Begin ********** #    
    merged.extend(right if right else left)
    # ********** End ********** #
    # 返回结果
    return merged

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值