百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT精选 > 正文

如何用Python实现快速排序算法(python快速排序原理)

ccwork 2025-04-10 21:09 9 浏览

快速排序(Quick Sort)是基于分治思想的经典排序算法,其核心思想是通过“基准值”(pivot)将数组分为两部分,递归地对子数组进行排序。它的平均时间复杂度为 (O(n log n)),是实际应用中最快的排序算法之一。以下是逐步讲解实现过程:

一、快速排序的原理

1. 核心思想

快速排序通过以下步骤实现:

  1. 选择基准值(Pivot):从数组中选择一个元素作为基准。
  2. 分区操作(Partition):将数组分为两部分: 左半部分的所有元素 ≤ 基准值; 右半部分的所有元素 ≥ 基准值。
  3. 递归排序:对左右两部分递归执行相同操作,直到子数组长度为1或0。

2. 示例演示

以数组 [5, 3, 8, 4, 2] 为例:

  1. 选择基准值:例如选择最后一个元素 2 作为基准。
  2. 分区操作:将小于等于 2 的元素移到左边,大于 2 的移到右边:[2, 3, 4, 5, 8] # 分区后基准值位置固定(索引0)
  3. 递归处理子数组:对左半部分 [2](已有序)和右半部分 [3,4,5,8] 重复上述步骤。

二、快速排序的实现步骤

1. 递归函数设计

快速排序通常通过递归实现,函数需接收待排序的子数组范围(如起始索引 low 和结束索引 high)。

2. 分区操作的实现

分区的核心是将元素与基准值比较,并交换位置:

  • 使用双指针法:一个指针(i)记录“小于等于基准值区域”的边界,另一个指针(j)遍历数组。
  • 当发现 nums[j] ≤ pivot 时,将 nums[j] 与 nums[i+1] 交换,i 向右移动一位。

3. 选择基准值

常见的基准值选择方式有:

  • 选择第一个元素;
  • 选择最后一个元素(如示例);
  • 选择中间元素;
  • 随机选择(优化性能,避免最坏情况)。

三、Python代码实现

3.1 基础版本(递归实现)

def quick_sort(arr, low, high):
    if low < high:
        # 分区操作,返回基准值的最终位置
        pivot_index = partition(arr, low, high)
        # 递归排序左右子数组
        quick_sort(arr, low, pivot_index - 1)
        quick_sort(arr, pivot_index + 1, high)

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[i], arr[j] = arr[j], arr[i]
    # 将基准值放到正确位置
    arr[i+1], arr[high] = arr[high], arr[i+1]
    return i + 1

# 测试
test_list = [64, 34, 25, 12, 22, 11, 90]
quick_sort(test_list, 0, len(test_list)-1)
print("排序后:", test_list)  # 输出:[11, 12, 22, 25, 34, 64, 90]

3.2 代码解释

  1. quick_sort 函数
  • 参数 low 和 high 表示当前子数组的起始和结束索引。
  • 如果 low >= high,说明子数组长度 ≤1,无需排序。
  • partition 返回基准值的索引 pivot_index,左右子数组分别递归排序。
  1. partition 函数
  • 基准值选择为最后一个元素 arr[high]。
  • 指针 i 初始指向 -1(表示“小于等于区域”为空)。
  • 遍历 j 从 low 到 high-1: 当 arr[j] ≤ pivot 时,i 向右移动一位,并与 arr[j] 交换位置。
  • 最后将基准值 pivot 与 arr[i+1] 交换,确保基准值位于正确位置。

四、优化版本(随机选择基准值)

为了避免最坏情况(如数组已有序时,时间复杂度退化为 (O(n^2))),可随机选择基准值:

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]
    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

五、测试与验证

5.1 正常测试

test_list = [64, 34, 25, 12, 22, 11, 90]
quick_sort(test_list, 0, len(test_list)-1)
print("排序后:", test_list)  # 输出:[11, 12, 22, 25, 34, 64, 90]

5.2 边界测试

  • 空列表:quick_sort([], 0, -1) → 无错误。
  • 单元素列表:quick_sort([5], 0, 0) → 返回 [5]。
  • 已排序列表:使用优化版本可避免最坏情况。

六、总结步骤

  1. 理解递归框架:快速排序通过递归不断缩小问题规模。
  2. 实现分区操作:通过双指针法交换元素,确保基准值正确归位。
  3. 选择基准值:随机选择可提升算法鲁棒性。
  4. 测试与调试:验证不同输入情况下的正确性。

七、练习题

  1. 基准值选择:将基准值改为第一个元素,观察代码是否仍能正确排序。
  2. 非递归实现:用栈模拟递归过程,实现迭代版本的快速排序。
  3. 稳定性验证:快速排序是不稳定排序,尝试构造测试用例验证(如 [4, 4, 2])。

通过以上步骤,可以逐步掌握快速排序的实现逻辑,并理解其高效性与潜在优化方向。

相关推荐

二十三、Java类与对象简介(java第十一章类和对象)

在Java编程语言中,类(Class)和对象(Object)是面向对象编程(OOP)的核心概念。描述类类是Java程序的基本组成单元,是对象的模板。类定义了对象的属性和方法。属性是对象的状态信息,而方...

设计模式-结构型-代理模式(proxy)

1.概念需要给对象提供一个代理以控制对该对象的访问,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介;根据代理类生成时机不同,分为静态代理和动态代理;静态代理代理类在编...

深度解析设计模式七大原则之——里氏替换原则

临近端午节,各位读者,你们假期行程安排好了吗?“菜鸟”已经做好决定了,谁都不能阻拦(产品经理也不行),“菜鸟”要好好在家休息三天。最近实在是太累了,一直在疯狂的加班。好了好了言归正传,开始我们的正文。...

Java代理模式详解:智能中介的编程艺术

一、生活场景中的代理思维想象您要租房子,但不想直接与房东打交道,这时房产中介就发挥作用了:1.中介帮您筛选房源(访问控制)2.签约前验证房东资质(预处理)3.协助办理合同手续(功能增强)4.处...

哪个创意最能打动你? 为你欣赏的“创意之星”投一票

这一期的《超级课堂·暑期特别活动》将评出5位“创意之星”,获得价值2000元的奖品。本期我们选登了部分中小学生在昙华林留下的创意作品,欢迎为最能打动你的作品投上一票。大众评审目前采取微信投票:扫描二维...

Netty基础—6.Netty实现RPC服务(netty reactor)

大纲1.RPC的相关概念2.RPC服务调用端动态代理实现3.Netty客户端之RPC远程调用过程分析4.RPC网络通信中的编码解码器5.Netty服务端之RPC服务提供端的处理6.RPC服务调用端实现...

静态代理和动态代理(静态代理和动态代理的优缺点)

1.什么是代理很多人肯定听过和看到过飞机票代理点,火车票代理点。那这些代理点干得事情就是帮航空公司,火车站出售火车票的工作。它们算是一个中间商。实际的服务不是由它们提供。而是由真正的服务商提供。通过这...

Java反射机制与Spring动态代理深度解析

一、Java反射机制原理剖析1.1反射的本质与实现基础Java反射(Reflection)是Java语言的核心特性,允许程序在运行时:动态加载类获取类结构元数据操作类属性和方法关键技术支撑:java...

Java 代理模式详解(java代理原理)

1.代理模式代理模式是一种比较好理解的设计模式。简单来说就是我们使用代理对象来代替对真实对象(realobject)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象...

SpringBoot全局异常处理:如何优雅应对多系统多格式错误响应需求

SpringBoot全局异常处理:如何优雅应对多系统多格式错误响应需求引言部分在微服务架构中,你是否曾为处理不同外部系统的异常响应而头痛?A系统要求返回JSON格式的:{code:1001,mes...

3分钟吃透代理技术!(代理一般都是怎么做)

最近有学员问了我一些问题,什么是代理,又该在什么地方使用。结合之前的讨论,这篇文章我们一起细致的讲解一下关于代理的一些问题。在Java中,代理通常分为两类:静态代理动态代理两者技术实现是不一样的,...

苏州网络维护 | 学习网络维护,从哪入手

我们想要学习网络维护,从哪入手呢?先带大家了解下网络维护1.培养基础知识:建立对计算机网络基本原理的理解。学习计算机网络的基础概念,如IP地址、子网掩码、路由器、交换机、协议等。2.学习网络技术:深入...

CAD如何快速一键编号?(cad如何一次性全部编号)

cad一键自动编号。·第一步,在命令行数abh空格。·第二步,打开自动编号对话框,选择用默认的图言编号,编号文字的高度根据图纸的大小设置零点八。当然如果图纸很大,设置比如十一百的有可能数字编号,这点很...

职场新人必知的10个高效工作法,助你快速升职加薪

初入职场,面对繁杂的工作任务和陌生的职场环境,如何才能快速适应并脱颖而出?以下是10个高效工作法,帮助职场新人提升工作效率,快速实现升职加薪的目标。---1.制定每日工作计划-推荐理由:每天开始...

《魔导英雄传说》新手攻略,快速升级,礼包码,最强阵容排列

《魔导英雄传说》新手攻略一、武将培养指南英雄选择与培养:英雄品质分为SSR、SR、A,优先培养SSR英雄,如张飞、孙尚香等核心英雄阵营搭配:同阵营上阵英雄越多,战力加成越高,建议优先培养同一阵营的英雄...