【漫画版】指挥官的排序战术:快速排序算法解密

news2025/1/11 6:56:38

作者介绍:10年大厂数据\经营分析经验,现任字节跳动数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python,欢迎探讨交流
欢迎加入社区:码上找工作
作者专栏每日更新:
LeetCode解锁1000题: 打怪升级之旅
python数据分析可视化:企业实战案例
漫画版算法详解
python源码解读
程序员必备的数学知识与应用

背景设定

现在你是一名军官,负责一个小队的战斗准备。小队有6名士兵,每个人的战斗力不同。为了最大化战斗效率,你需要根据士兵们的战斗力将他们从小到大排序
在这里插入图片描述

排序过程

  • 角色引入:六名士兵名字标识为①-⑥分别站成一行,每人盾牌显示着他们的战斗力。数值分别是20, 15, 10, 30, 25, 5。队伍看起来很混乱,没有任何顺序。

在这里插入图片描述
这时候你需要让他们根据战斗力从小到大排序你会怎么做?

  • 决策时刻
    • 作为军官,你决定选取第一名士兵(战斗力20)作为基准(基准士兵)。你让他举起手来,所有人的目光都集中在他身上。

在这里插入图片描述

  • 你命令:“比20战斗力低的,到他左边!比20战斗力高的,到他右边!动作快!”

  • 行动实施

    • 士兵们开始移动。士兵们根据你的命令重新排列自己的位置。战斗力为15和10的士兵迅速站到了左边,而战斗力为30和25的士兵则跑到了右边。战斗力为5的士兵最后一个,也加入到了左边。

在这里插入图片描述

  • 最终,基准士兵走到中间,正确的位置上。

  • 递归排序

    • 你接着指挥左边的小队和右边的小队分别进行相同的排序操作。左边的小队(15, 10, 5)和右边的小队(30, 25)也需要找到各自的基准,然后再次排序。
    • 你对左边的小队说:“15,你是这次的基准!”然后重复之前的排序指令。
    • 右边的小队也同样,选取30作为基准。

结局

  • 通过一系列的命令和移动,最终所有士兵都按照战斗力从低到高成功排序。
  • 排序完成后,队伍看起来整齐划一,每个士兵都知道自己的位置。你作为军官,对完成的排序感到满意,小队的战斗准备现在看起来更有序,准备迎接即将到来的挑战。

在这里插入图片描述
以上过程你作为军官用的就是快速排序的算法,看着步骤少是因为你能直接知道每个人的战斗力,并且每个人也知道其他人的战斗力,所以大家很快能排序好,实际通过代码实现的话步骤会更多一些,需要有更多的对比,因为没有提前知道其他人战斗力的前提在。

算法介绍

快速排序是一种非常高效的排序算法,由托尼·霍尔在1960年发明。它是一种使用分治策略的递归排序算法,目的是将一个大列表分为两个小列表,小列表中的元素分别比另一列表的元素小,然后递归地排序这两个子列表。

快速排序的基本步骤包括:

  1. 选择基准值(Pivot Selection)
    快速排序首先从数组中选择一个元素作为基准值,选择方法有多种,可以是第一个元素、最后一个元素、中间元素,或者随机元素,下图使用第一个元素。

  2. 分区操作(Partitioning)
    通过重新排列数组,使得比基准值小的元素全部移动到基准值的左侧,而比基准值大的元素全部移动到基准值的右侧。这个操作结束时,基准值就处于数组的中间位置。这一过程称为分区(Partitioning)。

  3. 递归排序子数组(Recursively Sorting the Sub-arrays)
    递归地将左侧子数组和右侧子数组进行排序。递归的基准情形是子数组的大小为0或1,这时子数组已经达到完全排序。

代码示例

def quicksort(nums, left, right):
    """
    递归执行快速排序,不断分割列表。
    
    参数:
    nums : list[int] -- 待排序的列表
    left : int -- 当前分割区域的左边界索引
    right : int -- 当前分割区域的右边界索引
    """
    if left < right:
        pi = partition(nums, left, right)
        print(nums, left,pi)
        quicksort(nums, left, pi - 1)   # 递归排序基准左侧的部分
        quicksort(nums, pi + 1, right)  # 递归排序基准右侧的部分

def partition(nums, left, right):
    """
    对数组进行划分,返回基准值的最终位置。
    
    参数:
    nums : list[int] -- 待排序的列表
    left : int -- 当前分割区域的左边界索引
    right : int -- 当前分割区域的右边界索引
    
    返回:
    int -- 基准值的最终位置索引
    """
    
    pivot = nums[left]  # 选择最左边的元素作为基准
    i = left + 1        # 将i初始化为基准右边的第一个元素
    j = right           # 将j初始化为最右边的元素
    while True:
        while i <= j and nums[i] <= pivot:       # i从左向右移动,直到找到一个大于基准的值
            i += 1
        while i <= j and nums[j] > pivot:        # j从右向左移动,直到找到一个小于基准的值
            j -= 1
        if i <= j:
            nums[i], nums[j] = nums[j], nums[i]  # 交换找到的两个值
        else:
            break
    nums[left], nums[j] = nums[j], nums[left]    # 将基准值进行交换
    return j                                     # 返回基准值的位置

# 测试代码
arr = [20, 15, 10, 25, 30, 5]
quicksort(arr, 0, len(arr) - 1)
print("Sorted array:", arr)

算法图解

partition1 按基准值进行左右分区
# 排序前 初始值
20, 15, 10, 25, 30,  5
# 第一次分区后 比基准值20小的在左边,比20大的在右边
5, 15, 10, 20, 25, 30

详细的动态GIF图参考,每个步骤变化时间2s,建议详细查看对比
在这里插入图片描述

partition2 递归排序左侧分区 5,15,10
# right = 3,指向20
quicksort(nums, left, pi - 1)   # 递归排序基准左侧的部分
# 第一次递归左分区 5,15,10
5, 15, 10, 20, 25, 30 
# 执行后还是返回 因为交换自己保持不变
5, 15, 10, 20, 25, 30
  1. i=1, 指向15,i 已经比基准值大,这时候保持=1不变
  2. j=2, 指向10,j 向左寻找比基准值小的值,这时候往左一直j=0的时候,这时候i>j,跳出循环
  3. j = left = 0,这时候5自己交换自己,这个步骤依然会执行
  4. 返回 j=0

在这里插入图片描述

partition3 递归排序左侧分区 15,10
# pi = 0,指向5
quicksort(nums, left, pi - 1)   # 递归排序基准左侧的部分
# 继续调用 quicksort,这时候 left < -1,不成立,所以走到右侧部分
quicksort(nums, pi + 1, right)

# 5, 15, 10, 20, 25, 30 排序 15,10 后
5, 10 ,15, 20, 25, 30
  1. i=2, 指向10,向右移动,指向20
  2. j=2, 指向10,小于基准值15,保持不变
  3. i>j,交换j和基准值

在这里插入图片描述
4. 交换后返回j=2
在这里插入图片描述

partition4 递归排序右侧分区 25, 30

同上忽略

快速排序的算法性能

  • 时间复杂度

    • 最好情况:(O(n log n)),当分区操作能将列表均等划分时。
    • 平均情况:(O(n log n)),对于随机排列的数组。
    • 最坏情况:(O(n^2)),当数组已经接近排序完成或完全逆序时,每次分区只能减少一个元素。
  • 空间复杂度

    • 最坏情况下,由于递归调用的栈空间,空间复杂度为 (O(n))。
    • 通过尾递归优化,可以将空间复杂度降低到 (O(\log n))。

快速排序的优点与缺点

  • 优点

    • 平均情况下非常高效。
    • 排序是就地进行的,除了递归栈,不需要额外的存储空间。
    • 高度优化的快速排序通常比其他 (O(n \log n)) 算法更快。
  • 缺点

    • 最坏情况下的性能较差。
    • 递归导致的堆栈溢出。
    • 非稳定排序,即相等的元素的原始顺序可能会被打乱。

算法改进

基于快速排序存在的缺点,我们一起来探讨一下这些问题,并提供几种改进策略,包括代码示例。

快速排序的基本问题

  1. 最坏情况性能:当输入数组已经接近排序完成或完全逆序时,快速排序的性能退化到 (O(n^2))。这种情况发生在基准值选取不当时,如始终选择第一个元素作为基准值。

  2. 重复元素处理:当数组中存在大量重复元素时,快速排序可能会进行不必要的比较和交换,导致效率降低。

改进策略

1. 优化基准值选择

一个好的基准值选择可以最大限度地确保数组被均等地分割,从而优化递归的深度和效率。

  • 三数取中法
    从数组的第一个元素、中间元素和最后一个元素中选择中位数作为基准值。这种方法通常可以防止对已经部分排序的数组进行排序时的性能退化。
2. 尾递归优化

快速排序通常通过递归实现,递归调用会消耗额外的栈空间。优化递归调用可以减少栈空间的使用。

  • 尾递归
    总是先递归较小的子数组,然后使用尾递归(或循环)处理较大的子数组。这可以确保递归栈的最大深度尽可能小。
3. 小数组切换到插入排序

插入排序在小数组上表现更优,因为它的常数因子较小,简单且快速。

  • 混合排序策略
    当数组大小减少到某个阈值(通常是10-20)时,切换到插入排序。
4. 处理重复元素

大量重复元素会减慢快速排序的速度,因为它们增加了不必要的比较和交换。

  • 三向切分快速排序
    这种变体通过将数组切分为三部分来处理含有大量重复元素的数组:小于基准值的元素、等于基准值的元素、以及大于基准值的元素。

代码示例:改进的快速排序

以下是一个集成了这些改进策略的快速排序的Python实现:

import random

def quicksort(arr, low, high):
    while low < high:
        if high - low < 16:  # 小数组使用插入排序
            insertion_sort(arr, low, high)
            break
        else:
            pivot_index = partition(arr, low, high)
            if pivot_index - low < high - pivot_index:
                quicksort(arr, low, pivot_index - 1)
                low = pivot_index + 1
            else:
                quicksort(arr, pivot_index + 1, high)
                high = pivot_index - 1

def partition(arr, low, high):
    mid = (low + high) // 2
    pivot = sorted([arr[low], arr[mid], arr[high]])[1]
    pivot_index = arr.index(pivot)
    arr[pivot_index], arr[high] = arr[high], arr[pivot_index]
    i = low
    for j in range(low, high):
        if arr[j] <= pivot:
            arr[i], arr[j] = arr[j], arr[i]
            i += 1
    arr[i], arr[high] = arr[high], arr[i]
    return i

def insertion_sort(arr, low, high):
    for i in range(low + 1, high + 1):
        key = arr[i]
        j = i - 1
        while j >= low and key < arr[j]:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key

array = [random.randint(0, 100) for _ in range(100)]
quicksort(array, 0, len(array) - 1)
print(array)

这段代码首先处理小数组的优化,并且使用三数取中法来选择基准值,以提高快速排序处理含有重复元素和部分排序数组的效率。此外,通过尾递归优化来减少栈深度。

快速排序的应用场景

快速排序适用于大数据集合,尤其是在平均性能很关键的场合。由于其就地排序的特性,也适合用于内存空间有限的系统。然而,对于小数组,其他 (O(n^2)) 的算法如插入排序可能更优,因此在实际应用中,快速排序常与其他排序算法结合使用。例如,在快速排序接近完成时切换到插入排序。

快速排序由于其优异的平均性能,广泛用于各种编程库和系统中,是处理大数据集的首选算法之一。

看完啦,如果本文对你有帮助,欢迎关注点赞,谢谢大家

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1661529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7. 链路日志打印实现设计

前言 在前面的文章中&#xff0c;我们已经实现了一个Starter包&#xff0c;能够在使用RestTemplate作为客户端请求工具时&#xff0c;记录调用链路信息。在本文&#xff0c;将实现Jaeger框架下的链路日志打印&#xff0c;也就是提供一个io.jaegertracing.spi.Reporter来将Span…

idea运行SpringBoot项目爆红提示出现:Java HotSpot(TM) 64-Bit Server VM warning...让我来看看~

在运行SpringBoot项目的时候&#xff0c;发现总有这个警告提示出现&#xff0c;有点强迫症真的每次运行项目都很难受啊&#xff01;那么今天便来解决这个问题&#xff01; 先来看一下提示内容&#xff1a;Java HotSpot(TM) 64-Bit Server VM warning: Options -Xverify:none an…

kaldi学习参考

HMM模型 https://www.cnblogs.com/baixf-xyz/p/16777438.htmlhttps://www.cnblogs.com/baixf-xyz/p/16777438.htmlGMM-HMM 基于GMM-HMM的语音识别系统https://www.cnblogs.com/baixf-xyz/p/16777439.html https://www.cnblogs.com/baixf-xyz/p/16777426.htmlhttps://www.cnbl…

Tomcat中服务启动失败,如何查看启动失败日志?

1. 查看 localhost.log 这个日志文件通常包含有关特定 web 应用的详细错误信息。运行以下命令查看 localhost.log 中的错误&#xff1a; sudo tail -n 100 /opt/tomcat/latest/logs/localhost.YYYY-MM-DD.log请替换 YYYY-MM-DD 为当前日期&#xff0c;或选择最近的日志文件日…

官宣:vAsterNOS正式发布!开放网络操作系统免费试用!

近期&#xff0c;vAsterNOS&#xff08;设备模拟器&#xff09;正式发布&#xff0c;可以满足用户快速了解 AsterNOS、体验实际操作、搭建模拟网络的需求&#xff0c;可运行在GNS3、EVE-NG等网络虚拟软件中。 AsterNOS 网络操作系统是星融元为人工智能、机器学习、高性能计算、…

AI换脸原理(3)——人脸对齐介绍

人脸对齐简介 人脸对齐其实包含两个步骤:人脸关键点检测、人脸对齐,英文术语有facial landmark和face alignment,主要用于精确标识眉毛、眼睛、鼻子、嘴巴以及人脸轮廓等特征部位。不同数据集对于关键点的数量有不同的设定,最少的是标记5个关键点,通常包括两只眼睛的瞳孔…

springboot-aop-学习笔记

什么是AOP&#xff1f; AOP英文全称&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实说白了&#xff0c;就是 需要 某个通用的方法时&#xff0c;可以创建一个模板&#xff0c;模板里面就有这些通用的方法&#xf…

mysql 其他类型转换为BIT

看官网说明,BIT没什么特殊之处。但实际操作却不能将任何其他类型字段转为BIT,下面两个都报语法错误 CAST(column AS BIT(1)) AS aa , CAST(column AS BIT) AS bb, BIT value则模式是VARBINARY b1 as cc, -- cc为VARBINARY类型 下面是《高性能MySQL(第四版)》中关于BIT类型的…

JDK不同版本里中国夏令时时间

什么是夏令时&#xff1f; 夏令时&#xff0c;&#xff08;Daylight Saving Time&#xff1a;DST&#xff09;&#xff0c;也叫夏时制&#xff0c;又称“日光节约时制”和“夏令时间”&#xff0c;是一种为节约能源而人为规定地方时间的制度&#xff0c;在这一制度实行期间所采…

物业收费管理小程序源码搭建/部署/上线/运营/售后/更新

一款基于FastAdminUniApp开发的一款物业收费管理小程序。包含房产管理、收费标准、家属管理、抄表管理、在线缴费、业主公告、统计报表、业主投票、可视化大屏等功能。为物业量身打造的小区收费管理系统&#xff0c;贴合物业工作场景&#xff0c;轻松提高物业费用收缴率&#x…

代码随想录算法训练营第六十天| LeetCode647. 回文子串 、516.最长回文子序列

一、LeetCode647. 回文子串 题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/0647.%E5%9B%9E%E6%96%87%E5%AD%90%E4%B8%B2.html 状态&#xff1a;已解决 1.思路 这道题我只想出来了暴力解法&#xff0c;动规解法并没有想出来。根据视频讲解才把它想出来。…

MT8370_联发科MTK8370(Genio 510)芯片性能规格参数

MT8370芯片是一款利用超高效的6nm制程工艺打造的边缘AI平台&#xff0c;具有强大的性能和功能。这款芯片集成了六核CPU(2x2.2 GHz Arm Cortex-A78 & 4x2.0 GHz Arm Cortex-A55)、Arm Mali-G57 MC2 GPU、集成的APU(AI处理器)和DSP&#xff0c;以及一个HEVC编码加速引擎&…

zip file is empty

从下找到报错的jar包。展开这个jar包&#xff0c;看下是否正常&#xff0c;正常的是能够展开看到一些文件夹以及里面的类&#xff0c;如下&#xff1a;如果不正常&#xff0c;就删除这个jar包&#xff0c;同时找到这个jar包在本地maven仓库的地址&#xff0c;也删除掉&#xff…

鸿蒙内核源码分析(文件句柄篇) | 你为什么叫句柄

句柄 | handle int open(const char* pathname,int flags); ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); int close(int fd);只要写过应用程序代码操作过文件不会陌生这几个函数,文件操作的几个关键步骤嘛,跟把大…

ssrf漏洞学习——基础知识

一、SSRF是什么&#xff1f; SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。 一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。&#xff08;正是因为它是由服务端发起的&#xff0c;所以它能…

天府锋巢直播产业基地构建成都电商直播高地

天府锋巢直播产业基地自成立以来&#xff0c;一直秉承着创新、协同、共赢的发展理念&#xff0c;吸引了众多直播企业纷纷入驻。随着直播产业的迅猛发展&#xff0c;改成都直播基地内的配套服务也显得尤为重要。本文将深入探讨入驻天府锋巢直播产业基地后&#xff0c;配套的直播…

Agent AI智能体:我们的生活即将如何改变?

你有没有想过&#xff0c;那个帮你设置闹钟、提醒你朋友的生日&#xff0c;甚至帮你订外卖的智能助手&#xff0c;其实就是Agent AI智能体&#xff1f;它们已经在我们生活中扮演了越来越重要的角色。现在&#xff0c;让我们一起想象一下&#xff0c;随着这些AI智能体变得越来越…

20240510每日后端---聊聊文件预览,doc,image,ppt转PDF预览

一、引入依赖 <dependency><groupId>com.aspose</groupId><artifactId>aspose-words</artifactId><version>15.8</version></dependency><dependency><groupId>com.aspose</groupId><artifactId>crac…

从头开始的建材类电商小程序开发指南

在当今数字化时代&#xff0c;小程序已经成为了许多企业推广和销售的重要渠道。对于建筑材料行业来说&#xff0c;开发一个属于自己的小程序商城不仅可以提升产品曝光度&#xff0c;还可以提供更好的用户购物体验。下面&#xff0c;我们将逐步教你如何开发建筑材料行业小程序。…

佛山市举办2024年护士节庆祝活动

“作为一名在护理岗位上工作了39年的护士,能够在退休前参加这样温情的护士节活动,获得一个纪念胸章和一份荣誉证书,让我很感动!”第七届“南粤好护士”、佛山市第一人民医院急诊科护士长罗银秋说道。5月10日下午,由佛山市卫生健康局主办、佛山市护理学会协办、佛山市第一人民医…