数据结构--知识点13--归并排序

1、 定义

先拆分再合并

  • 拆分时按照先对半,再将分出的子序列对半,以此类推,直到分为单个的元素
  • 合并时,合并的两个组来自原来拆分之前的组,先两两合并,合并的同时,将这两个元素排序
  • 再将合并后的序列们两两合并,合并时有两个游标,left、right,left指向左边序列的第一个元素,right指向右边序列的第一个元素,
  • 首先比较这两个元素的大小,如果左边小于右边,则将左边的元素放到合并的序列中的第一位,向右移动left一位,
  • 如果右边的更小,则将右边的元素放在合并的序列中的第一位,right游标向右移一位,继续比较两个游标所指的元素的大小;
  • 同样的方法将剩下的序列两两合并
  • 以此类推,直至最后合并为一个序列

2、python实现

先会分为两个,然后先处理左侧的子序列,将左侧的子序列排好序,再处理右侧的子序列;
在处理左侧的子序列时,再调用merge函数,将它分为两个子序列,然后再先处理左侧序列;
直到不可再分时,向下执行合并;
先合并为两个,然后合并右侧的;
然后合并为四个,先左侧再右侧;
左边的都排好后,再排右侧,与左侧的步骤相同

def merge_sort(alist):
    # 先拆分
    n=len(alist)
    mid=n//2
    if n <= 1:
        # mid为序列中间元素的索引,如果这个索引小于等于1 ,则表示此时已经拆分为单个元素的序列
        # 不做操作返回
        return alist
    # left、right表示采用归并排序后有序的新的序列
    left_li=merge_sort(alist[:mid]) #或list[:mid]
    right_li=merge_sort(alist[mid:])  # 或list[mid:]
    # 将两个有序的子序列合并为一个新的整体
    # merge(left,right)
    # 左右两个游标都从0索引开始
    left_pointer,right_pointer=0,0
    result=[]
    while left_pointer<len(left_li) and right_pointer < len(right_li):
        # 只要两个子序列的游标都没越界就一直执行
        if left_li[left_pointer] <= right_li[right_pointer]:
            result.append(left_li[left_pointer])
            left_pointer += 1
        else:
            result.append(right_li[right_pointer])
            right_pointer += 1
    # 当退出循环时,子序列一般还剩一个元素,将最后的这个元素加入result中
    result += left_li[left_pointer:]
    result += right_li[right_pointer:]
    return result


if __name__ == '__main__':
    list=[11,43,2,4,55,78,45,97,56,73,38]
    print(list)
    new_list=merge_sort(list)
    print(new_list)

结果:

[11, 43, 2, 4, 55, 78, 45, 97, 56, 73, 38]
[2, 4, 11, 38, 43, 45, 55, 56, 73, 78, 97]

3、时间复杂度

  • 最优时间复杂度:O(nlogn)
  • 最坏时间复杂度;O(nlogn)
  • 稳定性:稳定(只要在判断大小时,将小于改为小于等于,可以保证在等于的时候将左侧的值先放入序列)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值