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

作者介绍: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 += 1while i <= j and nums[j] > pivot:        # j从右向左移动,直到找到一个小于基准的值j -= 1if i <= j:nums[i], nums[j] = nums[j], nums[i]  # 交换找到的两个值else:breaknums[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 randomdef quicksort(arr, low, high):while low < high:if high - low < 16:  # 小数组使用插入排序insertion_sort(arr, low, high)breakelse:pivot_index = partition(arr, low, high)if pivot_index - low < high - pivot_index:quicksort(arr, low, pivot_index - 1)low = pivot_index + 1else:quicksort(arr, pivot_index + 1, high)high = pivot_index - 1def partition(arr, low, high):mid = (low + high) // 2pivot = sorted([arr[low], arr[mid], arr[high]])[1]pivot_index = arr.index(pivot)arr[pivot_index], arr[high] = arr[high], arr[pivot_index]i = lowfor j in range(low, high):if arr[j] <= pivot:arr[i], arr[j] = arr[j], arr[i]i += 1arr[i], arr[high] = arr[high], arr[i]return idef insertion_sort(arr, low, high):for i in range(low + 1, high + 1):key = arr[i]j = i - 1while j >= low and key < arr[j]:arr[j + 1] = arr[j]j -= 1arr[j + 1] = keyarray = [random.randint(0, 100) for _ in range(100)]
quicksort(array, 0, len(array) - 1)
print(array)

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

快速排序的应用场景

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

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

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

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

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

相关文章

stm32单片机学习路线

第一步 编程及硬件基础知识 1.掌握C语言基础 作为STM32的主要编程语言&#xff0c;C语言的基础知识是必不可少的。建议通过书籍、在线课程或者教学视频系统地学习C语言的基础知识&#xff0c;包括语法、数据类型、函数、指针等。 2.了解电子电路基础 对于单片机开发来说&…

面向对象 03:类与对象的创建、初始化和使用,通过 new 关键字调用构造方法,以及创建对象过程的内存分析

一、前言 记录时间 [2024-05-10] 系列文章简摘&#xff1a; Java 笔记 01&#xff1a;Java 概述&#xff0c;MarkDown 常用语法整理 Java 笔记 11&#xff1a;Java 方法相关内容&#xff0c;方法的设计原则&#xff0c;以及方法的定义和调用 面向对象 01&#xff1a;Java 面向对…

ESP32引脚入门指南(四):从理论到实践(PWM)

引言 ESP32 作为物联网领域的明星微控制器&#xff0c;除了强大的Wi-Fi和蓝牙功能&#xff0c;还内置了丰富的外设资源&#xff0c;其中就包括高级的PWM&#xff08;脉冲宽度调制&#xff09;功能。本文将深入探讨ESP32的PWM引脚&#xff0c;解析其工作原理&#xff0c;并通过…

2024年数维杯B题完整代码和思路论文讲解与分析

2024数维杯数学建模完整代码和成品论文已更新&#xff0c;获取↓↓↓↓↓ https://www.yuque.com/u42168770/qv6z0d/bgic2nbxs2h41pvt?singleDoc# 2024数维杯数学建模B题45页论文和代码已完成&#xff0c;代码为全部问题的代码 论文包括摘要、问题重述、问题分析、模型假设、…

G2 - 人脸图像生成(DCGAN)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目录 理论知识DCGAN原理 模型结构逻辑结构物理结构 模型实现前期准备1. 导入第三方库2. 修改随机种子(相同的随机种子&#xff0c;第i次随机的结果是固定的)3.…

Cocos creator实现《战机长空》关卡本地存储功能

Cocos creator实现《战机长空》关卡本地存储功能 Cocos creator在开放小游戏过程中&#xff0c;经常会出现设置关卡&#xff0c;这里记录一下关卡数据本地存储功能。 一、关卡设置数据 假如我们有关卡数据如下&#xff0c; let settings [ { level: 1, // 第1关 score: 0,…

SAM轻量化应用Auto-SAM、Group-Mix SAM、RAP-SAM、STLM

1. Auto SAM&#xff08;Auto-Prompting SAM for Mobile Friendly 3D Medical Image Segmentation&#xff09; 1.1 面临问题 医学背景&#xff1a; &#xff08;1&#xff09;与自然图像相比&#xff0c;医学图像的尺寸更小&#xff0c;形状不规则&#xff0c;对比度更低。&…

window10设置静态IP

右键桌面网络图标 点击属性 点击要查看的网络 点击详细信息 获得网络连接详细信息 右键WiFi符号 或者其他方式进入网络与internet中心 点击 WLAN 点击属性 点击编辑&#xff08;点击一个即可&#xff09; 选择手动将刚才的信息方进入即可 完成

多模态中的“单流模型”和“双流模型”

多模态预训练模型按照模型结构可以分为单流和双流两种结构。 单流是指图片和文本在embedding之后就融合在一起进入后续的transformer层。【先将信息fusion&#xff0c;然后再用一个model处理】双流是指文本和图片单独享有自己的transformer层&#xff0c;只在最后做轻量的融合…

VM虚拟机安装调试(步骤如下图)

VM虚拟机安装调试 随着一顿安装操作&#xff0c;还有enter键敲下&#xff0c;出现如下界面。

综述列表(~2024.05.10)

&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 每周末更新&#xff0c;完整版进群获取。 Q 群在群文件&#xff0c;VX 群每周末更新。

鲁教版六年级数学上册-笔记

文章目录 第一章 丰富的图形世界1 生活中的立体图形2 展开和折叠3 截一个几何体4 从三个方向看物体的形状 第二章 有理数及其运算1 有理数2 数轴3 绝对值4 有理数的加法5 有理数的减法6 有理数的加减混合运算7 有理数的乘法8 有理数的除法9 有理数的乘方10 科学计数法11 有理数…

【操作系统期末速成】​操作系统概述(定义|功能|特征)|发展阶段和分类|结构设计|概念补充

&#x1f3a5; 个人主页&#xff1a;深鱼~&#x1f525;收录专栏&#xff1a;操作系统&#x1f304;欢迎 &#x1f44d;点赞✍评论⭐收藏 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到…

4000字超详解Linux权限

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 在Linux当中权限的体现主要有两种 普通用户 超…

信息与未来2017真题笔记

T1. 龟兔赛跑 题目描述 兔子又来找乌龟赛跑啦&#xff01;同样的错误兔子不会犯两次&#xff0c;所以兔子提出赛跑的时候&#xff0c;乌龟就觉得这场比赛很不公平。于是兔子进一步放宽了条件&#xff0c;表示他可以在比赛开始以后先睡 t t t 分钟再开始追乌龟。 乌龟这下没…

VS ActiveQT 配置支持Halcon以及DLL调试

一、安装Halcon 首先需要 安装好Halcon 此时环境变量中应该有 HALCONARCH&#xff0c; HALCONEXAMPLES&#xff0c; HALCONIMAGES&#xff0c;HALCONROOT 二、VS C配置Halcon 2.1 include 在项目属性中加入两个 附加包含目录&#xff1a; $(HALCONROOT)/include $(HALCONROOT)/…

[附源码]石器时代_恐龙宝贝内购版_三网H5手游_带GM工具

石器时代之恐龙宝贝内购版_三网H5经典怀旧Q萌全网通手游_Linux服务端源码_视频架设教程_GM多功能授权后台_CDK授权后台 本教程仅限学习使用&#xff0c;禁止商用&#xff0c;一切后果与本人无关&#xff0c;此声明具有法律效应&#xff01;&#xff01;&#xff01;&#xff0…

完整版解答!2024年数维杯数学建模挑战赛B题

B题 生物质和煤共热解问题的研究 技术文档第一问1.1问题一分析1.2数据预处理1.3问题一Spearman相关性分析 数据代码资料获取 技术文档 第一问 1.1问题一分析 对于问题一&#xff0c;题目要求分析出正己烷不溶物对焦油产率、水产率、焦渣产率这三个指标是否有显著影响&#x…

会赚钱的人都在做这件事:你了解吗?

在我们日常生活的点滴中&#xff0c;以及在各种场合的交互中&#xff0c;利他思维始终扮演着不可或缺的角色。当我们追求合作与共赢时&#xff0c;单方面的自我立场显然是不够的&#xff0c;真正的关键在于换位思考&#xff0c;寻找并满足对方的需求。 互利互赢的核心理念正是利…

微软必应bing国内广告开户费用?如何开户投放?

当下搜索引擎广告无疑是企业触达潜在客户、提升品牌曝光度的重要途径之一&#xff0c;微软必应&#xff08;Bing&#xff09;作为全球第二大搜索引擎&#xff0c;尽管在国内市场份额上可能不敌某些本土巨头&#xff0c;但其独特的用户群体和国际影响力使其成为众多企业拓展市场…