排序算法之快速排序举例详解-python实现3版代码及改进过程

news2024/11/25 10:57:25

快速排序思想步骤:

1.找到一个基准值key

2.设置2个元素下标i=0和j=len-1

3.从后往前找到比key小的数num[j],从前往后找到比key大的数num[i](这里有个先后顺序)

4.交换这两个数:num[i],num[j]

5.继续重复该过程,直到i==j,完成一趟排序(循环结束条件)

6.以num[j]为界限,左右2边分别进行快速排序

图片来源于百度:

 

总结:

确定一个数字的准确位置,再递归它分出来的两个数组,直到递归规模缩小为1停止,最终整个数组会趋于有序。

注意:

i和j先后顺序不重要,但是每次都必须按照第一次的顺序来。如果第一次是i先走,后面的子分组快速排序也得i先走。

举例

num=[1,3,4,2,6,5]

1.找到基准值(首尾都行),key=1

2.num[i]=1,num[j]=5

3.j--找到比1小的第一个数

4.此时j=i(满足j<=i找不到),第一趟快速排序结束,数字1为有序。

此时顺序为:[1,3,4,2,6,5]

5.数字1左边的分组数据<=1左边分组已经有序,右边的分组继续进行快速排序

6.选择基准值key=3,num[i]=3,num[j]=5

7.j--找到比3小的第一个数,num[j]=2

8.i++找到比3大的第一个数,num[i]=4

9.交换num[i]和num[j]

此时顺序为:[1,3,2,4,6,5]

10.j--找比3小的第一个数,num[i]=2,此时j==i

11.交换key和num[j],发现3为分界线的左边 只有1个数字:2。(子分组,1为有序了)所以只需要对3右边进行快速排序。

此时顺序为:[1,2,3,4,6,5]

12.找基准值4,num[i]=4,num[j]=5

13.j--找到比4小的第一个数,找不到,此时i=j,num[i]==num[j]==key,4为有序

此时顺序为:[1,2,3,4,6,5]

14.找到基准值6,num[i]=6,num[j]=5

15.j--找到比6小的第一个数,5

16.i++找到比6大的第一个数,找不到,此时i=j,num[i]==num[j]==5

17.交换key和num[j]

此时顺序为:[1,2,3,4,5,6]

第4步和第17步体现了i和j顺序的作用。

由于我这里是j先走,所以,num[j]往前走到i==j还是没找到比key小的数的话,说明key是有序,不用交换。---对应第4步

当j--找到了比key小的第一个数(i不等于j时)之后,i++,直到i==j都没找到比key大的数,此时交换key和num[j]。----对应第17步

代码实现:

第一版代码(存在重复元素会陷入死循环)

1.设置基准值变量key,游标i,j。i是起始索引,j是结束索引

2.通过一个partition函数去完成num[i],num[j]的交换,函数返回索引mid,mid为划分子分组的界限

3.快速排序函数:参数为列表,开始索引,结束索引(用来传给partition函数获取mid索引)

4.以mid索引为界限,对左右两边子分组分别递归调用快速排序函数。

def partition(num,i,j):
    key=num[i]
    while i<j:
        while i<j and num[j]>key:
            j=j-1
        while i<j and num[i]<key:
            i=i+1
        num[i],num[j]=num[j],num[i]
    return j

def quick_sort(num,i,j):
    if i<j:
        mid = partition(num, i, j)
        quick_sort(num,i,mid-1)
        quick_sort(num, mid + 1, j)
# num=[1,3,4,2,6,5]
num = [5, 7, 4, 6, 3, 1, 2, 9, 8]
i=0
j=len(num)-1
quick_sort(num,i,j)
print(num)


partition函数:

1.当i小于j的时候,判断num[j]>key就一直执行j=j-1,直到找到一个num[j]<=key

2.再判断i<j并且num[i]>key,一直执行i=i+1,直到找到一个num[i]>=key

3.交换num[i]和num[j]的值

当列表内没有重复元素时,初版代码完美实现。

第二版代码(重复元素测试通过)

但是当列表中存在重复元素,会跳过partition中两个内循环,所以并不会有i和j的更改。

直接在外面的循环中一直交换2个元素,就陷入了死循环。于是,我在第一版代码的基础上又做了一些改进得到第二版代码。

思路沿用第一版,具体实现区别在于partition函数。

partition函数:

1.设置基准值key=num[i](我设置的左边的值为基准值)

2.循环比较num[j]和key的大小,如果num[j]>=key,执行j=j-1。当num[j]<key的时候,停止循环,然后把num[j]赋值给num[i](此时比key大的数放到左边去了)

3.循环比较num[i]和key的大小,如果num[i]<=key,执行i=i+1。当num[i]>key的时候,停止循环,把num[i]赋值给num[j](此时比key小的数放到右边了)

4.把key的值赋值给num[i],相当于key为中间值,第一轮结束,小的数已分到了左边,大的数分到了右边。

def partition(num,i,j):
    key=num[i]
    while i<j:
        while i<j and num[j]>=key:
            j=j-1;
        num[i]=num[j]
        while i<j and num[i]<=key:
            i=i+1
        num[j]=num[i]
    num[i]=key
    return i

def quick_sort(num,i,j):
    if i<j:
        mid = partition(num, i, j)
        quick_sort(num,i,mid-1)
        quick_sort(num, mid + 1, j)
# num=[1,3,4,2,6,5]
num=[1,0,2,2,1,0]
# num = [5, 7, 4, 6, 3, 1, 2, 9, 8]
i=0
j=len(num)-1
quick_sort(num,i,j)
print(num)


在没有重复元素的时候,2-3步相当于第一版代码的外循环里面的交换。

当有重复元素的时候,也会交换,但是不会陷入上一版代码的死循环了。

上一版代码由于没有重复元素,所以内循环里,>=和<=的效果都一样。这版代码是有重复元素的,所以得加上=。

因为如果j=j-1找到小于key的元素,就要进行交换。如果是找到相等元素,可以不进行交换。

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

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

相关文章

如何在PADS Logic中查找器件

PADS Logic提供类似于Windows的查找功能&#xff0c;可以进行器件的查找。 &#xff08;1&#xff09;在Logic设计界面中&#xff0c;将菜单显示中的“选择工具栏”进行打开&#xff0c;如图1所示&#xff0c;会弹出对应的“选择工具栏”的分栏菜单选项&#xff0c;如图2所示。…

数据库信息速递 MONGODB 6.0 的新特性,更多的查询函数,加密查询,与时序数据集合 (译)...

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到3群&#xff08;共…

Shell脚本函数 实验

Shell 函数 命令序列按照格式写在一起&#xff0c;用函数的方式调用并进行重复使用命令序列。这就是它的核心作用 使用函数可以避免代码重复&#xff0c;函数可以将大的工程分割成若干小的功能模块&#xff0c;提高代码的可读性。 函数的基本格式写法有两种&#xff0c;如下&…

零钱兑换 II(力扣)动态规划 JAVA

给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带符号整数。 示例…

预付费电表收费系统

预付费电表收费系统是一种先进的电表管理系统&#xff0c;它能够帮助电力公司更加高效地管理电表收费&#xff0c;提高用电效率&#xff0c;降低能源浪费。本文将从以下几个方面介绍预付费电表收费系统的特点和优势。 一、预付费电表收费系统的原理 预付费电表收费系统是指用户…

5分钟给你破解这套10万赞的生产教程,访谈乔布斯的AI对话数字人视频是怎么做的

本期是赤辰第16期AI项目拆解栏目&#xff1b; 底部准备了7月粉丝福利&#xff0c;看完可以领取&#xff1b; 上周给粉丝们讲解AI动图说话月涨粉20万的案例并给出保姆式教程&#xff0c;粉丝反馈很热烈&#xff0c;都觉得AI强大&#xff0c;有些学员给自己账号做视频&#xff…

ACME申请SSL证书

1.开放443端口 firewall-cmd --permanent --add-port443/tcp # 开放443端口 firewall-cmd --reload # 重启防火墙(修改配置后要重启防火墙)2.安装ACME # 安装acme curl https://get.acme.sh | sh -s email你的邮箱地址 # 别名 alias acme.sh~/.acme.sh/acme.sh3.使用ACME申请…

rabbitMQ杂记

消息队列应用场景 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合&#xff0c;异步消息&#xff0c;流量 削锋等问题实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性&#xff1a; 解耦&#xff1a; 异步&#xff1a; 削峰&#xff1a; 常…

全面深入理解MySQL自增锁

&#x1f497;推荐阅读文章&#x1f497; &#x1f338;JavaSE系列&#x1f338;&#x1f449;1️⃣《JavaSE系列教程》&#x1f33a;MySQL系列&#x1f33a;&#x1f449;2️⃣《MySQL系列教程》&#x1f340;JavaWeb系列&#x1f340;&#x1f449;3️⃣《JavaWeb系列教程》…

Gin+Gorm练手小项目bubble清单企业级结构剖析

概述 本项目来源于Qimi老师的小清单项目——基于gingorm开发的练手小项目&#xff0c;通过该项目可初识go web开发该有的姿势。笔者对代码有些许修改&#xff0c;以下是项目成功运行的截图&#xff0c;主要功能有添加&#xff0c;删除&#xff0c;确认&#xff0c;查看待办事项…

APP测试学习之Android模拟器Genymotion安装配置不上解决方法以及adb基本使用

Android模拟器Genymotion安装配置不上解决方法以及adb基本使用 Genymotion下载安装配置遇见的问题解决方法adb基本使用 Genymotion下载 1.首先进入官网 https://www.genymotion.com/ 2.在官网注册一个账号 https://www-v1.genymotion.com/account/login/ 3.下载 https://www.g…

Linux之设备树解耦架构解读-V1.0

术语和缩略语 本文档使用了以下术语和缩略语 Dts&#xff1a;DTS即Device Tree Source&#xff0c;是一个文本形式的文件&#xff0c;用于描述硬件信息。一般都是固定信息&#xff0c;无法变更&#xff0c;无法overlay。 Dtsi&#xff1a;可以理解为dts的公共部分&#xff0…

【编程技巧--函数指针回调函数】

1&#xff0e;什么是函数指针 在C语言中&#xff0c;一个函数在编译时被分配一个入口地址(第一条指令的地址),我们可以将地址赋给一个指针,这样,指针变量持有函数入口地址,它就指向了该函数,所以称这种指针为指向函数的指针,简称函数指针。 我们在编写代码的时候可以用函数名…

教你快速安装Bootstrap

目录 Bootstrap简介Bootstrap的下载Bootstrap的使用 Bootstrap简介 Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作&#xff0c;基于HTML、CSS、JavaScript开发的简洁、直观、强悍的前端开发框架&#xff0c;它会使Web开发更加快捷Bootstrap框架的优点 开发…

【电路原理学习笔记】第4章:能量与功率:4.3 电阻的额定功率

第4章&#xff1a;能量与功率 4.3 电阻的额定功率 额定功率是一个电阻器可以消耗的最大功率&#xff0c;且保证其不会被过多的热量损坏或改变其阻值。额定功率与电阻值无关&#xff0c;主要由电阻的材料成分、物理尺寸和形状决定。在其他条件相同的情况下&#xff0c;电阻的表…

Redis分布式锁的演变历程

什么时候用分布式锁 当并发去读写一个【共享资源】的时候&#xff0c;我们为了保证数据的正确&#xff0c;需要控制同一时刻只有一个线程访问。 分布式锁就是用来控制同一时刻&#xff0c;只有一个 JVM 进程中的一个线程可以访问被保护的资源。 分布式锁入门 分布式锁应该满足…

MySQL数据库之高级SQL语句

目录 一.MySQL语句前言 1.1 按关键字排序 1.2 环境准备 1.3单字段排序 1.3.1升序 1.3.2降序 1.3.3 order by还可以结合where进行条件过滤 ​编辑 1.4多字段排序 1.4.1查询学生信息先按兴趣id升序排列&#xff0c;相同分数的&#xff0c;id按照降序排列 1.4.2查询学生信息先…

Win10环境下Android Studio中运行Flutter HelloWorld项目

一、引言 Android Studio是Android的官方IDE(Integrated Development Environment)。它专为Android而打造&#xff0c;可以加快开发速度&#xff0c;为Android设备构建最高品质的应用。 Flutter是Google推出并开源的移动应用开发框架&#xff0c;主打跨平台、高保真、高性能。开…

Linux--stdin、stdout、stderr的文件描述符fd

stdin的文件描述符是 &#xff1a;0 stdout的文件描述符是 &#xff1a;1 stderr的文件描述符是 &#xff1a;2 证明&#xff1a; #include <stdio.h>int main() {printf("stdin: %d\n",stdin->_fileno);printf("stdout: %d\n",stdout->…

instsrv 注册 windows 系统服务

注册步骤 Win r 打开 cmd 窗口执行 instsrv.exe myserver C:\Windows\System32\srvany.exe 示例&#xff1a; instsrv.exe nginx C:\Windows\System32\srvany.exe win r 运行 regedit 进入注册表&#xff0c;依次找到以下路径 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\S…