当前位置: 首页 > news >正文

【快速排序】| 详解快速排序 力扣912

🎗️ 主页:小夜时雨
🎗️专栏:快速排序
🎗️如何活着,是我找寻的方向

优雅

目录

  • 1. 题目解析
  • 2. 代码

1. 题目解析

题目链接: https://leetcode.cn/problems/sort-an-array/

在这里插入图片描述

我们上道题讲过快速排序的核心代码,建议先看一下这道题:颜色分类 https://leetcode.cn/problems/sort-colors/description/

快速排序的核心代码区间就是数组分三块, 所以还是十分重要的, 接下来我们再来分析一下分块这个过程:

  • i 作为基准 key , 用三个变量分别标记, i 标记遍历原数组的位置, left 标记 0 区域的最右边位置, right 标记右边 2 区域最左边的位置.
  • i 遍历数组, nums[i] < key 时, 交换 left + 1 和 i 位置的值, i++;
  • 碰见 == key 的, 直接 i++;
  • nums[i] > key 时, 交换 right - 1 和 i 位置的值, 此时注意没有 i++, 仍要进行判断 i 位置的值(详情看颜色分类这道题: https://leetcode.cn/problems/sort-colors/description/

接下来我们来说一下快速排序的实现过程

快速排序具体实现过程:

  1. 首先我们先确定一个 key,作为基准进行比较.
  2. 三个变量进行标记, 分别是 i 标记原数组遍历的位置, left 标记 < key 区域的最右边位置, right 标记 > key 区域的最左边位置.
  3. i 遍历原数组, nums[i] < key 时, 交换 left + 1 和 i 位置的值, 之后 i++, left++;
  4. nums[i] == key 时, i++, 不做任何交换
  5. nums[i] > key 时, 交换 right - 1 和 i 位置的值, 之后 right - 1, 注意 i 不变
  6. 这个之后把数组分成了三块, 中间一块都是等于 key 的不用处理, 之后递归处理左边区域和右边区域, 也都是同样的处理方式, 就是递归. (看后续的代码更容易理解).

看下面的分析图可能会更容易理解:

在这里插入图片描述

  • 关于 key 的选择, 我们用随机的方式选择基准元素最好, 分三块的思想当全部元素都一样的时候, 此时只需遍历一遍就可以排好数组了.

在这里插入图片描述

  • 也就是说我们想让整体有序,先把数组分为三块, 左边是小于 key 的区域, 中间是等于 key 的区域, 右边是大于 key 的区域. 这样是一个大致有序的数组了
  • 以左区间为例:得先让左区间进行有序,让左区间有序就得让左区间进行划分, 分成三块, 之后左边区间又逐渐有序了.
  • 就这样一直划分下去,直到划分不了区间就是有序了, 那么这个时候左边区间就是已经排好序了, 右边区间同理.
  • 我们发现这个过程其实有点像是二叉树的前序遍历, 前让中间区域有序(类比是根节点), 之后再是左区间, 右区间有序.
  • 归并排序有点像是二叉树的后序遍历,左右区间有序之后(类比先遍历左右子树),合并之后整体才会有序(遍历根节点)。

2. 代码

看下面的代码对照着上面的流程解析可能会更加的清楚。

	// 快速排序public int[] sortArray3(int[] nums) {int n = nums.length;// 传入下标qsort(nums, 0, n - 1);return nums;}    /*** l, r 表示下标, 要排序的下标* * @param nums* @param l* @param r*/private void qsort(int[] nums, int l, int r) {// 循环终止条件if(l >= r) return;// 数组分三块, 不是从 0 开始, 因为要划分好多次// left 表示小于 key 的最右侧, right 表示大于 key 的最左侧int left = l - 1, right = r + 1, i = l;// 随机生成 key, 注意这个位置, nextInt(r - l + 1) + l 别忘了加 lint key = nums[new Random().nextInt(r - l + 1) + l];// 数组分三块, 核心代码while(i < right) {if(nums[i] < key) swap(nums, i++, ++left);else if (nums[i] == key) i++;else swap(nums, i, --right);}// 分完之后, 再分左侧的和右侧的qsort(nums, l, left);qsort(nums, right, r);}private void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}

归并排序: https://blog.csdn.net/Jin__Wang/article/details/139811604

🎗️🎗️🎗️ 好啦,到这里有关本题的分享就没了,如果感觉做的还不错的话可以点个赞,关注一下,你的支持就是我继续下去的动力,我们下期再见,拜了个拜~ ☆*: .。. o(≧▽≦)o .。.:*☆

http://www.lryc.cn/news/387246.html

相关文章:

  • 游戏推荐: 植物大战僵尸杂交版
  • 微调和rag的区别?
  • CVPR讲座总结(二)-探索图像生成基础模型的最新进展探索多模态代理的最新进展:从视频理解到可操作代理
  • 为什么要禁用透明大页面
  • Element 页面滚动表头置顶
  • 对于CDA一级考试该咋准备??!
  • 如何使用PHP和Selenium快速构建自己的网络爬虫系统
  • intellij idea安装R包ggplot2报错问题求解
  • 【C++】初识C++(一)
  • 【智能算法】目标检测算法
  • python 中 json.load json.loadd json.dump json.dumps 详解
  • 【UE 网络】专用服务器和多个客户端加入游戏会话的过程,以及GameMode、PlayerController、Pawn的创建流程
  • 磁盘分区工具(fdisk 和 parted)区别及操作笔记
  • VisualStudio2019受支持的.NET Core
  • Java——IO流(二)-(1/7):字符流-FileReader、FileWriter、字符输出流的注意事项(构造器及常用方法、小结)
  • Spring循环依赖问题——从源码画流程图
  • Android SurfaceFlinger——动画播放准备(十五)
  • Zynq7000系列FPGA中的DMA控制器简介(二)
  • 获取 url 地址栏 ? 后面的查询字符串,并以键值对形式放到对象里面
  • List接口, ArrayList Vector LinkedList
  • 探讨数字化背景下VSM(价值流程图)的挑战和机遇
  • Conda跨平台环境迁移
  • 全面掌握 Jackson 序列化工具:原理、使用与高级配置详解
  • mathtype7.4永久激活码密钥及2024最新破解版注册码附安装教程
  • 【SQL】优化慢 SQL的简单思路
  • 禁止浏览器对input的自动填充和填充提示(适用于谷歌、火狐、Edge(原IE浏览器)等常见浏览器)
  • 鸿蒙项目实战-月木学途:1.编写首页,包括搜索栏、轮播图、宫格
  • 深入浅出:npm常用命令详解和实践
  • 山东大学-科技文献阅读与翻译(期末复习)(选择题+翻译)
  • 二分查找:自定义 upper_bound、lower_bound