Python学习算法系列(5):归并排序与堆排序

Python学习算法系列(5):归并排序与堆排序

1. 引言

在前几篇博客中,我们学习了插入排序快速排序。本篇博客将继续介绍两种常见的排序算法:

  • 归并排序(Merge Sort)
  • 堆排序(Heap Sort)

我们将介绍它们的基本原理、代码实现以及性能分析。


2. 归并排序(Merge Sort)

2.1 归并排序原理

归并排序是一种采用分治法的排序算法,其基本思想是:

  1. 将数组分为两部分,分别进行排序。
  2. 将已排序的两部分合并成一个有序数组。

归并排序的关键在于“合并”操作,即将两个已排序的子数组合并成一个有序数组。

2.2 归并排序代码实现

def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    mid = len(arr) // 2  # 找到中间位置
    left = merge_sort(arr[:mid])  # 对左半部分递归排序
    right = merge_sort(arr[mid:])  # 对右半部分递归排序
    return merge(left, right)  # 合并排序结果

def merge(left, right):
    result = []
    i = j = 0
    # 合并左右两部分
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result

# 测试归并排序
arr = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = merge_sort(arr)
print("排序后的数组:", sorted_arr)  # 输出 [11, 12, 22, 25, 34, 64, 90]

2.3 归并排序时间复杂度

归并排序的时间复杂度为:

  • 最好情况:O(n log n)
  • 最坏情况:O(n log n)
  • 平均情况:O(n log n)

归并排序的空间复杂度是 O(n),因为需要额外的空间来存储合并后的数组。


3. 堆排序(Heap Sort)

3.1 堆排序原理

堆排序是一种基于堆数据结构的排序算法,堆是一个完全二叉树,其每个父节点都大于或小于其子节点(最大堆或最小堆)。堆排序的过程如下:

  1. 构建最大堆(或最小堆),使得根节点是最大(或最小)元素。
  2. 将根节点(最大元素)与堆的最后一个元素交换,然后重新调整堆。
  3. 重复该过程,直到所有元素排序完成。

3.2 堆排序代码实现

def heapify(arr, n, i):
    largest = i
    left = 2 * i + 1  # 左子节点
    right = 2 * i + 2  # 右子节点

    # 判断左子节点是否比根节点大
    if left < n and arr[left] > arr[largest]:
        largest = left
    # 判断右子节点是否比当前最大值大
    if right < n and arr[right] > arr[largest]:
        largest = right

    # 如果最大值不是根节点,则交换并继续调整堆
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def heap_sort(arr):
    n = len(arr)
    # 建立最大堆
    for i in range(n//2 - 1, -1, -1):
        heapify(arr, n, i)
    
    # 逐个交换根节点与最后一个元素,并调整堆
    for i in range(n-1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)

# 测试堆排序
arr = [64, 34, 25, 12, 22, 11, 90]
heap_sort(arr)
print("排序后的数组:", arr)  # 输出 [11, 12, 22, 25, 34, 64, 90]

3.3 堆排序时间复杂度

堆排序的时间复杂度为:

  • 最好情况:O(n log n)
  • 最坏情况:O(n log n)
  • 平均情况:O(n log n)

堆排序的空间复杂度是 O(1),因为堆排序是原地排序,不需要额外的空间。


4. 排序算法的性能比较

以下是 归并排序堆排序 与其他常见排序算法的时间复杂度比较:

算法时间复杂度(最好情况)时间复杂度(最坏情况)空间复杂度
冒泡排序O(n)O(n^2)O(1)
选择排序O(n^2)O(n^2)O(1)
插入排序O(n)O(n^2)O(1)
快速排序O(n log n)O(n^2)O(log n)
归并排序O(n log n)O(n log n)O(n)
堆排序O(n log n)O(n log n)O(1)

5. 总结

  • 归并排序:是一种稳定的排序算法,适用于大规模数据,时间复杂度为 O(n log n),但需要额外的空间来存储中间数组。
  • 堆排序:是一种原地排序算法,空间复杂度 O(1),适用于大规模数据,尽管时间复杂度也是 O(n log n),但性能通常不如快速排序。
  • 排序算法优化:对于大规模数据,归并排序和堆排序是非常有效的选择。

📢 下一篇 Python学习算法系列(6):基数排序与计数排序,敬请期待!🚀

💡 如果你喜欢这篇文章,欢迎点赞、收藏,并关注本系列!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值