Python 快速排序(一文讲透)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在编程世界中,排序算法如同整理房间的魔法工具,帮助开发者将混乱的数据变得井然有序。Python 快速排序作为经典排序算法之一,以其高效的性能和直观的逻辑,成为开发者必须掌握的核心技能。无论是处理海量数据、优化程序效率,还是理解算法设计的思想,快速排序都能提供极具启发性的视角。本文将从零开始,通过案例、代码和直观的比喻,带您一步步揭开快速排序的奥秘。


一、快速排序的基本概念与核心思想

1.1 什么是快速排序?

快速排序(QuickSort)是一种基于分治法(Divide and Conquer)的高效排序算法。它的核心思想是通过“分而治之”将一个大问题分解为多个小问题,最终快速解决。

形象比喻
想象你要整理一个杂乱的书架,快速排序就像这样操作:

  1. 选基准:先挑一本中间的书作为“基准点”。
  2. 分左右:把比它薄的书放在左边,比它厚的放在右边。
  3. 递归整理:对左右两边的小书架重复上述步骤,直到每摞书都只有一本。

1.2 快速排序的特性

  • 时间复杂度:平均情况为 O(n log n),最坏情况为 O(n²)(当数据已排序或逆序时)。
  • 空间复杂度:平均 O(log n)(递归栈空间),最坏 O(n)。
  • 稳定性:不稳定(相同值的元素可能因分区顺序不同而改变相对位置)。

二、快速排序的实现步骤详解

2.1 步骤分解

快速排序的实现可以分为以下三个关键步骤:

步骤 1:选择基准值(Pivot)

从数组中选择一个元素作为基准值。常见的选择方式包括:

  • 取第一个元素;
  • 取最后一个元素;
  • 取中间元素;
  • 随机选择(推荐,以减少最坏情况的概率)。

步骤 2:分区操作(Partition)

将数组分为两部分:

  • 左区:所有元素 ≤ 基准值;
  • 右区:所有元素 ≥ 基准值。
    基准值最终会被放置到正确的位置,使其左边的元素都小于它,右边的元素都大于它。

步骤 3:递归排序子数组

对左区和右区重复上述步骤,直到子数组长度为 1 或 0。


三、Python 实现快速排序的代码示例

3.1 基础版实现

以下是一个简单的快速排序函数实现:

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]  # 选择中间元素作为基准值
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)

代码解释

  • 当数组长度 ≤ 1 时,直接返回原数组(递归终止条件)。
  • 使用列表推导式将元素分为左区(小于基准值)、中间区(等于基准值)、右区(大于基准值)。
  • 递归排序左区和右区,最终合并结果。

测试案例

print(quick_sort([3, 6, 8, 10, 1, 2, 1]))  

3.2 原地排序优化

基础版实现虽然直观,但每次递归都会生成新列表,导致额外内存开销。通过原地排序可以优化空间复杂度:

def partition(arr, low, high):
    pivot = arr[high]  # 选择最后一个元素作为基准值
    i = low - 1
    for j in range(low, high):
        if arr[j] <= pivot:
            i += 1
            arr[i], arr[j] = arr[j], arr[i]  # 交换元素
    arr[i+1], arr[high] = arr[high], arr[i+1]
    return i + 1

def quick_sort_inplace(arr, low=0, high=None):
    if high is None:
        high = len(arr) - 1
    if low < high:
        pi = partition(arr, low, high)
        quick_sort_inplace(arr, low, pi-1)
        quick_sort_inplace(arr, pi+1, high)
    return arr

关键改进点

  • 分区函数:通过交换元素实现原地分区,避免创建新列表。
  • 基准值选择:这里选择最后一个元素作为基准值,但也可以随机化(如 random.choice)。

测试案例

arr = [3, 6, 8, 10, 1, 2, 1]
print(quick_sort_inplace(arr))  

四、快速排序的优化与进阶

4.1 随机选择基准值

为了避免最坏情况(如输入数组已排序),可随机选择基准值:

import random

def partition_optimized(arr, low, high):
    # 随机选择基准值并交换到末尾
    pivot_index = random.randint(low, high)
    arr[pivot_index], arr[high] = arr[high], arr[pivot_index]
    pivot = arr[high]
    # 后续步骤与原分区函数相同...

4.2 尾递归优化

通过将最后的递归调用改为迭代形式,减少栈溢出风险:

def quick_sort_tail_recursive(arr, low=0, high=None):
    if high is None:
        high = len(arr) - 1
    stack = [(low, high)]
    while stack:
        low, high = stack.pop()
        if low >= high:
            continue
        pi = partition(arr, low, high)
        stack.append((pi+1, high))  # 先保留右区,后处理左区(栈的特性)
        stack.append((low, pi-1))
    return arr

五、快速排序的性能分析与适用场景

5.1 时间复杂度对比

以下是几种常见排序算法的时间复杂度对比:

算法名称最好情况平均情况最坏情况空间复杂度稳定性
快速排序O(n log n)O(n log n)O(n²)O(log n)不稳定
归并排序O(n log n)O(n log n)O(n log n)O(n)稳定
冒泡排序O(n)O(n²)O(n²)O(1)稳定

结论:快速排序在平均情况下表现优异,但需注意最坏情况的规避,适合处理大规模无序数据。


5.2 实际应用案例

场景:电商平台需对商品销量进行实时排序。

sales = [1200, 850, 3400, 150, 4500, 2200]
sorted_sales = quick_sort(sales)
print("排序后的销量:", sorted_sales)

六、常见问题与调试技巧

6.1 快速排序的递归深度问题

当输入数据接近有序时,递归深度可能达到 O(n),导致栈溢出。可以通过以下方式解决:

  • 三数取中法:选择数组首、中、尾三个元素的中位数作为基准值;
  • 改为迭代实现:如前文提到的尾递归优化。

6.2 如何调试快速排序代码?

  • 打印中间结果:在分区函数中添加 print 语句,观察数组变化;
  • 单元测试:编写测试用例覆盖边界情况(如空数组、单元素数组、全相同元素)。

结论

Python 快速排序凭借其简洁的逻辑和高效的性能,成为开发者工具箱中的重要一员。通过本文的逐步讲解,您不仅掌握了快速排序的实现原理,还学会了如何通过优化技巧提升其鲁棒性。无论是处理日常的数据排序任务,还是为算法面试做准备,快速排序都是值得深入理解的算法。

建议读者通过以下实践进一步巩固:

  1. 尝试修改基准值选择策略,观察性能差异;
  2. 将快速排序与归并排序、堆排序进行性能对比;
  3. 在实际项目中替换原有排序逻辑,体验效率提升。

通过持续练习,您将真正掌握这一经典算法的力量。

最新发布