【算法基础】快速排序(模板)

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在学习c++和算法
✈️专栏:【C/C++】算法
🐋 希望大家多多支持,咱一起进步!😁
如果文章有啥瑕疵
希望大佬指点一二
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 一、快速排序步骤
  • 二、代码模板
  • 三、边界问题
    • 3.1 为什么要指针要指向边界,然后使用`do while`而不直接使用 `while`?
    • 3.2 为什么移动移动`i`和`j`的条件分别是 `< x` 和 `> x`,而不是一开始所说的`<= x`和`>= x`
    • 3.3 当分界点为左端点x = a[0]
    • 3.4 当分界点为右端点a[n - 1]
    • 3.5 当x = a[(l + r) / 2]
    • 3.6 当x = a[(l + r + 1) / 2]
  • 四、算法分析
  • 五、总结

一、快速排序步骤

在这里插入图片描述

  1. 第一步:要确定一个分界点x分界点可以取左端a[0]、右端a[n - 1]、中间值a[(l+r) / 2]或者是随机值
  2. 第二步:调整区间。快速排序的思想是分治。 所以,要使分界点左部分≤x,右部分≥x (升序)。
  3. 第三步:递归处理左右两个部分。

Q:如何将数组一分为二,使≤x在左边,≥x在右边呢?

法一:暴力做法

  1. 开辟两个数组分别是c[]q[]
  2. 再扫描原数组a[],把≤x的元素放在c[]中,≥x放在q[]中。
  3. 最后先将c[] 放入a[],再把b[]放入a[]

法二:双指针做法(推荐)

  1. 首先先让指针i++向中间寻找元素,直到指向的a[i] ≥x停下
  2. 同样地,再将指针 j - -向中间寻找元素,直到指向的a[j] ≤x停下
  3. 当条件满足 i < j,就将这两个元素交换(swap)
  4. 当循环结束,指针j最终就一定会在指针i的前面

举个例子来验证双指针算法:

假设要升序排序 1 3 5 2 4,并设分界点x = 3

  • 先移动i,直到i指向的元素≥3停下
    在这里插入图片描述
  • 再移动j,直到j指向的元素≤3停下​​
    ​​在这里插入图片描述
  • 当条件满足i < j,则交换
    在这里插入图片描述
  • 接着继续移动i,直到i指向的元素≥3停下
    在这里插入图片描述
  • 再移动j ,直到j 指向的元素≤3停下
    在这里插入图片描述
    最后,我们会发现,j最终停在了i的前面

二、代码模板

void quick_sort(int a[],int l,int r)
{// //如果数组中就一个数或者没有数,就没必要再排序(递归出口) if(l >= r) return; // 1. 确定分界点xint x = a[(l + r) / 2]; // 2. 调整区间// 将指针指向边界(边界问题)int i = l - 1, j = r + 1;while (i < j){do i++; while(a[i] < x);do j--; while(a[j] > x);if (i < j) swap(a[i],a[j]);}// 3. 递归处理左右两部分//递归处理左部分,也就是<x的部分quick_sort(a, l, j);//递归处理右部分,>x的部分quick_sort(a, j + 1, r);
}

三、边界问题

3.1 为什么要指针要指向边界,然后使用do while而不直接使用 while?

原因是:以while为例,假设数组中有 相同的元素,会发生死循环

举个例子,假设排序 3 1 3 2 4,并设分界点x = 3

  1. 先判断i
    在这里插入图片描述
  2. 再判断j
    在这里插入图片描述
  3. 当条件 i < j ,交换元素
    在这里插入图片描述
  4. 接着再判断i ,而j不满足条件会继续指向3
    在这里插入图片描述
    最后你会发现,就会一直死循环交换3

3.2 为什么移动移动ij的条件分别是 < x> x,而不是一开始所说的<= x>= x

如果分界点x,恰好是数组中最大值,会导致越界。
同理,如果分界点又恰好是数组中最小值,也会导致越界。

3.3 当分界点为左端点x = a[0]

递归部分就不能使用quick_sort(a, l, i - 1)quick_sort(a,i,r),会导致 死递归
举个例子
当数组只有12在排序时,左端点分界点x = 1
在这里插入图片描述
因此,到时候ij会同时指向1
此时i = 0j = 0l = 0r = 1
对于第一个递归:quick_sort(a,0,- 1),相当于数组内没有值可以交换。
对于第二个递归:quick_sort(a, 0, 1),这时,就一直就这两个数交换,导致死递归。

3.4 当分界点为右端点a[n - 1]

递归部分就不能使用quick_sort(a,l,j)quick_sort(a,j + 1,r),会导致 死递归
和例子3.3是一样的
当数组内部还是只有12两个元素,这时右端点x = 2
在这里插入图片描述
因此,到时候ij会同时指向2
此时i = 1j = 1l = 0r = 1
第一个递归quick_sort(a,0,1),这时,就一直就这两个数交换,导致死递归

3.5 当x = a[(l + r) / 2]

递归部分不能使用quick_sort(a,l,i - 1)quick_sort(a,i,r)
还是同样的例子,假设还是只有12在排序,这时分界点x = a[(0 + 1)/2] = a[0] = 1,这种情况就和3.3是一样的了。

3.6 当x = a[(l + r + 1) / 2]

递归部分就不能使用quick_sort(a,l,j)quick_sort(a,j + 1,r)
还是同样的例子,数组还是只有1,2两个元素,这时分界点x = a[(0 + 1 + 1)/2] = a[1] = 2,这中情况就和3.4是一样的

四、算法分析

  1. 时间复杂度
    快速排序最坏时间复杂度是O(n^2),最好的时间复杂度为O(nlogn)

  2. 空间复杂度
    空间复杂度是O(1),因为没有用到额外开辟的集合空间。

  3. 算法稳定性
    快速排序是不稳定的排序算法。因为我们无法保证相等的数据按顺序被扫描到和按顺序存放。

五、总结

  1. x=a[l]或者x=a[(l + r) /2],只能用
//左半部分递归
quick_sort(a, l, j); 
//右半部分递归
quick_sort(a,j + 1, r);
  1. x=q[r] or x=q[l+r + 1>>1],只能用
//左半部分递归
quick_sort(a,l,i - 1);
//右半部分递归
quick_sort(a, i, r);

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elasticsearch:倒数排序融合 - Reciprocal rank fusion

警告&#xff1a;此功能处于技术预览阶段&#xff0c;可能会在未来版本中更改或删除。 Elastic 将尽最大努力修复任何问题&#xff0c;但技术预览中的功能不受官方 GA 功能的支持 SLA 约束。 倒数排序融合&#xff08;RRF&#xff09;是一种将具有不同相关性指标的多个结果集组…

java.sql.Time 字段时区问题 Mybatis 源码分析

java.sql.Time 字段时区问题 系列文章目录 第一章 初步分析 第二章 Mybatis 源码分析 第三章 Jackson 源码分析 意想不到的Time处理类 文章目录 java.sql.Time 字段时区问题 系列文章目录前言Mybatis源码阅读1. ResultSetImpl部分源码&#xff1a;2. SqlTimeValueFactory部分…

【AUTOSAR】BMS开发实际项目讲解(二十九)----电池管理系统电池充放电功率控制与SOC

电池充放电功率控制 关联的系统需求 Sys_Req_3901、Sys_Req_3902、Sys_Req_3903、Sys_Req_3904; 功能实现描述 电池充放电功率控制主要包括以下内容&#xff1a; 60S可用功率 参见[CELL] 30S可用功率 参见[CELL] 10S可用功率 参见[CELL] SOP算法 ID Description ASI…

Nginx(3)nginx的Rewrite功能

nginx跨域 Rewrite功能配置Rewrite的相关命令Rewrite的案例域名跳转域名镜像独立域名目录自动添加/合并目录防盗链 Rewrite功能配置 Rewrite是Nginx服务器提供的一个重要基本功能&#xff0c;是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。 注意:Nginx服…

【iVX】在百花齐放的低代码平台中独领风骚

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后端的开发语言A…

openssl版本升级与降级

openssl版本升级与降级 flyfish 环境 Ubuntu 22.04 1.1.1升级3.1.1 查看openssl版本 openssl versionOpenSSL 1.1.1t 7 Feb 2023https://www.openssl.org/source/ 编译和安装 ./config --prefix/usr/local/openssl311 make -j8 make install进入/usr/local/openssl311/l…

Web服务器群集:Nginx+Tomcat实现负载均衡与动静分离集群

目录 一、理论 1.多实例 2.Nginx负载均衡 3.Nginx动静分离 4.配置NginxTomcat负载均衡 5.配置NginxTomcat动静分离集群 6.Nginx 四层代理配置 二、实验 1.配置NginxTomcat负载均衡 2.、配置NginxTomcat动静分离集群 三、问题 1.服务器群集与集群的区别 四、总结 一…

【数据结构】栈和队列(栈篇)

目录 1.栈的概念及结构 2.栈的实现 2.1栈的结构体定义 2.2栈的常用接口函数 &#x1f43e;栈的初始化 &#x1f43e;插入数据 &#x1f43e;删除数据 &#x1f43e;取栈顶元素 &#x1f43e;判断栈是否为空 &#x1f43e;计算栈的大小 &#x1f43e;栈的销毁 2.3完…

Java设计模式之结构型-适配器模式(UML类图+案例分析)

目录 一、概念 二、UML类图 1、类适配器 2、对象适配器 三、角色设计 四、代码实现 案例一 案例二 五、总结 一、概念 将一个类的接口转换为另一个接口&#xff0c;使得原本由于接口不兼容的类进行兼容。 适配器模式主要分为类适配器模式和对象适配器模式&#xff0…

android:RadioGroup的使用

一、前言&#xff1a;工作中会遇到勾选不同的类型&#xff0c;获得不同的数据。仅以此笔记记录。 二、上代码&#xff1a; 新建一个Activity public class RadioHorizontalActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {private Text…

conda、python与人工智能学习过程中的一些基础性问题

一个不知名大学生&#xff0c;江湖人称菜狗original author: Jacky LiEmail : 3435673055qq.com Time of completion&#xff1a;2023.6.30 Last edited: 2023.6.30 目录 pip install XXX与conda install XXX的区别 conda install xxx pip install xxx 为什么要建立虚拟环境…

Mysql架构篇--Mysql(M-M) 主从同步

文章目录 前言一、M-M 介绍&#xff1a;二、M-M 搭建&#xff1a;1.Master1&#xff1a;1.1 my.cnf 参数配置&#xff1a;1.2 创建主从同步用户&#xff1a;1.3 开启复制&#xff1a; 2.Master2&#xff1a;2.1 my.cnf 参数配置&#xff1a;2.2 创建主从同步用户&#xff1a;2.…