快速排序【模板+边界处理】

news/2024/4/26 7:46:59/文章来源:https://blog.csdn.net/weixin_54202947/article/details/127626727

全文目录:

  • 😃快速排序的思想
  • 😕 快速排序演示图
  • 😴 代码模板
  • ❗️ `i` 和 `j` 的取值和循环处理 ❗️
    • 🗽 `i` 和 `j` 的取值 🗽
    • 🗽 循环条件判断 🗽
  • 💢 边界问题 💢
    • 😵 什么是边界问题 😵
    • 😵 如何处理边界问题 😵
    • 😵 为什么要这样处理边界问题 😵
      • 😫 区间划分问题 😫
      • 😫 取最值问题 😫
      • 😫 `mid` 取中间值时是否需要 +1 问题 😫
  • ✨ 总结 ✨

😃快速排序的思想

快速排序的思想就是取数组中的某一个值,暂且叫做mid(但不一定是中间值),取两个指针,一个指针指向数组的首元素(left),暂且叫做i,一个指针指向数组的尾元素(right),暂且叫做j

i < j的条件下,执行以下操作:

  1. i从左往右走,寻找>=mid的值
  2. right从右往左走,寻找<=mid的值
  3. 两者都找到后,在i< j的情况下交换两者的值
  4. 继续上述操作

当循环条件不满足时,也就是 i >= j 时,数组会被分成两个区间,切记不是平分数组的两区间。可能会有一下几种情况:

  • 可能是二等分,即[left, (left + right) / 2] 和 [(left + right) / 2 + 1, right]
  • 也能是[left, left] 和 [left + 1, right]
  • 或者[left, right - 1] 和 [right, right]

情况还有很多种,但是不管基于哪种情况都会满足左区间的值全部<=mid,右区间的值全部满足>=mid

然后分别取左区间和右区间为一个新的数组,重复上述操作。当区间被划分到不存在时直接返回。

😕 快速排序演示图

快速排序动态演示图

😴 代码模板

void quick_sort(int a[], int left, int right) 
{if (left >= right) return;int i = left - 1;    int j = right + 1;int mid = a[(left + right + 1) / 2];while (i < j) {do i++; while (a[i] < mid);do j--; while (a[j] > mid);if (i < j) swap(a[i], a[j]);}quick_sort(a, left, i - 1);quick_sort(a, i, right);
}

❗️ ij 的取值和循环处理 ❗️

🗽 ij 的取值 🗽

由于在进行交换完之后,ij都需要往中间走,所以不如在寻找交换值的时候先让这两个指针往中间靠一下,再进行判断,这样可以节省这一操作,简化代码。

但这样做的话,如果ij的初始值为leftright 的话,就会跳过最左值和最右值的比较,所以需要让i比left小1j比right大1

当然,也可以根据个人个人习惯,在交换完之后先玩中间走,代码如下:

void quick_sort(int a[], int left, int right) 
{if (left >= right) return;int i = left;    int j = right;int mid = a[(left + right + 1) / 2];while (i < j) {while (a[i] < mid) i++;while (a[j] > mid) j--;if (i < j) {swap(a[i], a[j]);i++;j--;}}quick_sort(a, left, i - 1);quick_sort(a, i, right);
}

🗽 循环条件判断 🗽

上述代码中寻找中间值的代码中while循环的条件能不能改成下面这样呢?

do i++; while (a[i] <= mid);
do j--; while (a[j] >= mid);
if (i < j) swap(a[i], a[j]);

答案是不可以的,如果数组中的值都是相等的话,在 i 有可能会变成 r + 1 ,然后执行 a[i] <= mid 语句,会导致数组访问越界。

💢 边界问题 💢

快速排序最让人头疼的莫非就是边界了,如果边界处理不当很有可能导致死循环和数组越界问题。

😵 什么是边界问题 😵

边界问题就是在划分新区间时使用左右指针中的哪一个来划分区间的问题,以及mid的取值问题。

😵 如何处理边界问题 😵

对于边界问题主要有一下节点需要注意:

  • 使用左指针来划分区间时,新区间为:[left, i - 1], [i, right]
  • 使用右指针来划分区间时,新区间为:[left, j], [j + 1, right]
  • 使用左指针来划分区间时,mid的值不能取最左值
  • 使用右指针来划分区间时,mid的值不能取最右值
  • 使用中间值((left + right) / 2)作为mid时:如果使用左指针来划分区间,mid需要 +1。

😵 为什么要这样处理边界问题 😵

😫 区间划分问题 😫

这里以使用左指针来划分区间为例:

因为在循环结束时,数组被分为左右两个区间,i 的左边就是 <=mid的,a[i]的值一定是 >=mid的,所以[left, i - 1], [i, right]可以很好地将左右两个区间划分开来。

同理,使用右指针来划分区间时也是一样的道理。

😫 取最值问题 😫

这里以使用左指针来划分区间时,取最左值为例:

在循环结束时,因为 i 的最大值是 right 可能没有动,这时,左区间 [left, i - 1] 没有任何问题,但右区间 [i, right] 就会发生问题,因为 i 可能为 left ,会发生无限递归!!

举个栗子🤔:

mid 的值为 a[left],数组中的元素 a[left, right] > mid 循环结束后,i == left, j == left , 那么右区间就还会是原数组。

同理,在使用 j 来划分区间时 mid 取最右值也是一样的。

😫 mid 取中间值时是否需要 +1 问题 😫

这个问题就是取最值问题的一个派生问题,当数组中只有两个元素的话 mid 就会取到最左值,所以在使用左指针来划分区间时 mid 需要 +1,避免取到最左值的情况。

✨ 总结 ✨

快速排序的思想容易理解,但是边界问题却让人屡屡出错,所以我总结了一下几点经验:

1. 使用哪个指针,划分对应区间时需要往它起始的位置挪一下

使用左指针划分区间时,划分左区间 i 需要往左移一个位置,
使用右指针划分区间时,划分右区间 j 需要往右移一个位置。

2. 有加必有减

意思是如果mid +1 了,意味着使用的是做区间,那么对应的使用的左指针 i 就需要 -1。

有上面两句话基本上就可以搞定大部分的边界问题

完结散花🌈🌈🌈
在这里插入图片描述

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

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

相关文章

Scala数组常用函数(2)

函数&#xff08;1&#xff09;&#xff1a;Scala数组常用函数&#xff08;1&#xff09;_后季暖的博客-CSDN博客 目录 四十六.-def isTraversableAgain: Boolean 四十七.-def iterator: collection.Iterator[T] 四十八.-def last: T 四十九.-def lastIndexOf(elem: T):…

计算机毕业设计(66)php小程序毕设作品之视频点播学习在线教育小程序系统

基于微信小程序的毕业设计题目&#xff08;12&#xff09;php在线教育视频点播学习小程序(含开题报告、任务书、中期报告、答辩PPT、论文模板) 项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于微信小程序视频点播系统&#xff0c;前台用户使用小程序&a…

【2022秋招面经】——数据库

参考链接&#xff1a; 1. 20个数据库常见面试题讲解 2. MySQL数据库面试题&#xff08;2020最新版&#xff09; 小林coding-MySQL 小林coding-Redis 文章目录数据库关系型数据库和非关系型数据库数据库高并发环境解决方案数据库外键的优缺点百万级别或以上的数据如何删除如何保…

计算机毕业设计(64)php小程序毕设作品之校园运动场地预约小程序系统

项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于微信小程序运动场地预约系统&#xff0c;前台用户使用小程序&#xff0c;后台管理使用基PHPMySql的B/S架构&#xff1b;通过后台添加开放的场地类型&#xff08;比如羽毛球、篮球、网球等&#xff09;、…

混合与面剔除帧缓冲

混合混合不同物体的多种颜色为一种颜色,所以透明度能让我们看穿物体,透明度一般由alpha颜色值来决定的,透明度为1-alpha值。首先试着使用有一部分透明的草贴图.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);//用来说明现在…

JavaScript 52 JavaScript this 关键词

JavaScript 文章目录JavaScript52 JavaScript this 关键词52.1 this 是什么&#xff1f;52.2 方法中的 this52.3 单独的 this52.4 函数中的 this&#xff08;默认&#xff09;52.5 函数中的 this&#xff08;严格模式&#xff09;52.6 事件处理程序中的 this52.7 对象方法绑定5…

2022年马丁·加德纳聚会数学魔术分享之《加加减减的奥秘》回顾

早点关注我&#xff0c;精彩不错过&#xff01;2022.10.30&#xff0c;本年度的线上马丁加德纳聚会如约举行。随着大家对线上这种活动方式的适应和不变的对趣味数学的热爱&#xff0c;今年聚会的规模&#xff0c;无论是线下还是线上&#xff0c;都朝着欣欣向荣的方向发展着。详…

【CV】第 7 章:使用 YOLO 进行对象检测

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

【历史上的今天】11 月 1 日:蒂姆·库克诞生;Amazon.com 注册域名;比特币问世

整理 | 王启隆 透过「历史上的今天」&#xff0c;从过去看未来&#xff0c;从现在亦可以改变未来。 今天是 2022 年 11 月 1 日&#xff0c;在 1949 年的今天&#xff0c;中国科学院在北京成立&#xff0c;它是中国最高学术领导机构的综合研究中心&#xff0c;首任院长是郭沫若…

【C++】继承- 赋值兼容转换、虚基表

前言 Hi~大家好呀&#xff01;欢迎来到我的C系列学习笔记&#xff01; 我上一篇的C笔记链接在这里哦~&#xff1a;【C】模板的非类型参数、特化、分离编译_柒海啦的博客-CSDN博客 C类与对象博客在这里哦~&#xff1a;【C】类和对象_柒海啦的博客-CSDN博客_c类和对象 本篇&#…

【异步系列五】关于async、await、promise、微任务、宏任务的执行顺序解析【最终篇】

前段时间总结了几篇关于异步原理、Promise原理、Promise面试题、async/await 原理的文章&#xff0c;链接如下&#xff0c;感兴趣的可以去看下&#xff0c;相信会有所收获。 一篇文章理清JavaScript中的异步操作原理 Promise原理及执行顺序详解 10道 Promise 面试题彻底理解…

输入输出、文件读写、数据类型

package chapter01 /* object:关键字&#xff0c;声明一个单例对象&#xff08;伴生对象&#xff09;*/ object HelloWorld {/*main方法&#xff1a;从外部可以直接调用执行的方法def 方法名称&#xff08;参数名称&#xff1a;参数数据类型&#xff09;:方法返回值类型 { 方法…

2.8 标准输入与格式化输出

文章目录1. Input 标准输入1.1 标准输入1.2 阻塞状态1.3 输入提示1.4 获取输入字符串1.5 输入版本差异1. Python3 输入数据类型2. Python2 输入数据类型2. Print 格式化输出2.1 输入2.2 sep 参数2.3 end 参数2.4 快捷写法2.5 格式化输出1. 语法格式2. 字典形式传值3. 元组形式传…

什么是GPT

什么是GPT 参考资料&#xff1a; https://zhuanlan.zhihu.com/p/350017443 https://zhuanlan.zhihu.com/p/106462515 https://www.cnblogs.com/yifanrensheng/p/13167796.html https://blog.csdn.net/weixin_45577864/article/details/119651372 Generative Pre-trained T…

这可能是你需要的vue考点梳理

对 React 和 Vue 的理解&#xff0c;它们的异同 相似之处&#xff1a; 都将注意力集中保持在核心库&#xff0c;而将其他功能如路由和全局状态管理交给相关的库&#xff1b;都有自己的构建工具&#xff0c;能让你得到一个根据最佳实践设置的项目模板&#xff1b;都使用了Virt…

Golang学习之路3-基础认识(下)

文章目录前言一、数组1.定长数组2.不定长数组二、map1.使用关键字 map 来声明2.使用 make 来声明3.添加元素4.检索key的value是否存在5.删除元素6.遍历map7.map的注意点在这里插入图片描述三、指针1.使用指针& 及 *2.空指针四、循环与条件判断1.循环2.条件判断前言 学习一…

Go语言函数

什么是函数 func main() {fmt.Println("hello,world")//调用函数fmt.Println(add(1, 2)) }// func 函数名&#xff08;参数&#xff0c;参数。。。&#xff09;&#xff0c;函数调用返回值类型&#xff08;&#xff09; func add(a, b int) int {c : a breturn c }函…

Ray tracing 光线追踪 之 embree ,从入门到精通 02 从源码编译与安装

1. 下载预编译的ispc&#xff0c;安装 网址&#xff1a; https://ispc.github.io resources -> github page 进入ispc 的github的release页&#xff1a;Releases ispc/ispc GitHub 找到一个预编译好了的ispc&#xff0c;其中在windows平台上是&#xff1a;https://github…

Redis缓存穿透、击穿、雪崩介绍

面试高频&#xff0c;工作常用 缓存穿透&#xff08;查不到&#xff09; 概念 用户想要查询一个数据&#xff0c;发现redis内存数据库没有&#xff0c;也就是缓存没有命中&#xff0c;于是向持久层数据库查询。发现也没有&#xff0c;于是本次查询失败&#xff0c;当用户很多的…

GO实现跳跃表

GO实现跳跃表 文章目录GO实现跳跃表跳跃表介绍跳跃表的实现跳跃表的结构创建跳跃表跳跃表的插入和删除跳跃表的排名操作跳跃表的区间操作完整实现跳跃表介绍 跳跃表&#xff08;skiplist&#xff09;是一种有序的数据结构&#xff0c;它通过建立多层"索引"&#xff…