(python)归并排序

前言

        归并排序(Merge Sort)较早为通用存储程序计算机设计的算法之一。它由冯·诺依曼(John von Neumann)在 1945 年发表的“101 报告”时提出,后于 1951 年完成的 EDVAC 计算机上应用了这一算法。

目录

基本思想

复杂度

一般步骤

应用场景

代码

递归方式

非递归方式 

真题


基本思想

        将一个数组不断地分成两半,分别对这两半进行排序,然后将排序好的两半合并起来。

复杂度

一种稳定的排序算法,即相同元素的相对顺序在排序前后不会改变。

时间复杂度 O(nlogn) 

递归方式 空间复杂度 O(n + logn) 

非递归方式 空间复杂度 O(n) 

一般步骤

  1. 分解:将待排序的数组不断地“一分为二”,直到每个子数组只包含一个元素。
  2. 递归排序与合并:在分解过程完成后,递归地对每个子数组进行排序,并将两个相邻的已排序子数组合并成一个有序的新数组。合并时,通过比较两个子数组的元素,按顺序放入新数组中。
  3. 结束条件:当所有子数组都合并完毕,最终得到的数组就是完全有序的。

应用场景

归并排序由于其稳定、高效的特点。

只要涉及到对大量数据进行排序且对稳定性有要求的场景,归并排序都可能是一个合适的选择。

  1. 大规模数据排序:当需要对大量数据进行排序时,归并排序的  时间复杂度能够保证较好的性能。
  2. 外部排序:当数据量太大而无法一次性放入内存时,归并排序常用于外部排序算法中。可以将数据分成多个较小的块,在内存中对每个块进行排序,然后逐步将这些已排序的块合并。
  3. 分布式系统:在分布式计算环境中,数据可能分布在不同的节点上。归并排序的思想可以用于合并来自不同节点的已排序数据段。
  4. 数据库操作:数据库在对大型数据表进行排序或合并操作时,可能会使用类似归并排序的策略。
  5. 排序算法比较和教学:由于归并排序具有清晰的分治思想和相对简单的实现逻辑,常被用于算法教学和不同排序算法的性能比较。
  6. 多路归并:在处理多个已排序的数据流(如文件)并将它们合并为一个有序数据流的情况下,归并排序的思想可以扩展为多路归并。

代码

递归方式

自上而下的归并排序 通常更直观,容易理解和实现,因为它利用了递归的思想。

        通过递归的方式将数组不断地分成两半,直到子数组的大小为 1 ,然后再将这些子数组逐步合并成有序的数组。它从整个数组开始,逐步向下细分,然后再向上合并。        

def merge_sort(arr):
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left_half = merge_sort(arr[:mid])
    right_half = merge_sort(arr[mid:])

    return merge(left_half, right_half)

def merge(left, right):
    result = []
    left_index = 0
    right_index = 0

    while left_index < len(left) and right_index < len(right):
        if left[left_index] < right[right_index]:
            result.append(left[left_index])
            left_index += 1
        else:
            result.append(right[right_index])
            right_index += 1

    result.extend(left[left_index:])
    result.extend(right[right_index:])

    return result

非递归方式 

自下而上的归并排序  通常在迭代实现中更高效,特别是在一些情况下可以避免递归带来的额外开销(如函数调用的开销、栈空间的使用等)。

def merge(seq, low, mid, high):
    """ 合并两个已排序好的子序列 """
    global sort_times
    left = seq[low:mid]
    right = seq[mid:high]
    k = 0  # left 的下标
    j = 0  # right 的下标
    result = []  # 保存合并后的结果
    while k < len(left) and j < len(right):
        if left[k] <= right[j]:
            result.append(left[k])
            k += 1
        else:
            result.append(right[j])
            j += 1

    result += left[k:]
    result += right[j:]
    seq[low:high] = result


def merge_sort(seq):
    i = 1  # 子数组长度,从1开始
    while i < len(seq):
        low = 0
        # print(f'------ start {i} ----')
        while low < len(seq):
            mid = low + i
            high = min(low + 2 * i, len(seq))  # 防止超出数组长度
            if mid < high:
                merge(seq, low, mid, high)
            low += 2 * i  # 移动到下一组要合并的子数组

        # print(f'------ end {i} ----')
        i *= 2  # 子数组长度翻倍

运行样例

array_A = [5, 2, 4, 7, 1, 3, 4, 6]
array_B = merge_sort(array_A)
print(array_B)
# [1, 2, 3, 4, 4, 5, 6, 7]

真题

用归并算法对数组<3, 1, 4, 1, 5, 9, 6, 5>进行从小到大排序,则需要进行多少次数组元素之间的比较?(2011年上半年)

答案:14次

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Marst·Writer

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

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

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

打赏作者

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

抵扣说明:

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

余额充值