快速排序/快速选择算法
一.快速排序
1.基本介绍
快速排序(Quicksort〉是对冒泡排序的一种改进,都属于交换排序。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分(每次选择中轴值),中轴值左边的元素小于中轴值,中轴值右边的元素全部大于中轴值(但不要求有序),然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

2.基本思路
我们每次选择一个中轴值,将中轴值和最后一个元素交换位置,对left到right-1的元素进行交换,当r<=l,此时l停留到的位置和right位置上的元素(中轴值)进行交换,这个时候,l停留的位置上是中轴值,并且左边的元素比中轴值小,右边的元素比中轴值大,然后递归对左边和右边的元素进行快速排序,直到left>=right的时候停止,此时数组便是有序的了.
1.关于中轴值的选择
大部分的可能给出的是选择第一个元素作为中轴值,但是这种做法有一定的弊端,如果是数组的元素是随机排序的,是可以接受的,但是如果数组的元素是预排序或者反序的,这样所有的元素不是全被划入到中轴值左边,就是划入到中轴值右边,那么时间复杂度就会很高
一种有效的方法时是采用随机产生一个下标为[left,right]的下标,这种情况下虽然可能会产生上面描述的情况,但总的来说可能性还是很小的.
还有一种方法是:三数中值分割法,我们选取三个数,使得三个数的最大值作为中轴值进行分割,一般来说我们选取左端,中端,右端的三个元素的终止作为中轴值,这种选取的方法还是
2.小数组情形
对于很小的数组(数组元素个数小于20),快速排序不如插入排序,因为快速排序是递归的.我们通常的做法是对于小的数组采用插入排序,一种好的截止范围是n=10,同时这种做法也避免了三数中值分割法的错误情况,比如最终数组的元素只有一个元素或者两个元素,而无法三数分割
3.时间复杂度
快速排序的平均时间复杂度:O(nlogn)
最好情况:O(nlogn)
最坏情况:O()
空间复杂度:O(logn)
同时快速排序不稳定,也就说元素相同的时候,原本在前边的元素,可能会最终被排序到后边
3.代码实现
1.随机值分割
public void quickSort(int[] nums, int left, int right) {if (left >= right)return;int index = (int) (left + Math.random() * (right - left + 1));int pivot = nums[index];//随机值生成indexswap(nums, index, right);int l = left, r = right - 1;while (true) {while (l < right && nums[l] < pivot) {//找到第一个比pivot大的数l++;}while (r > 0 && nums[r] > pivot) {//r--;}if (l < r)swap(nums, l++, r--);elsebreak;}swap(nums, l, right);quickSort(nums, left, l - 1);quickSort(nums, l + 1, right);}
2.三数中值分割法
public static final int CUTOFF = 10;public int median(int[] nums, int left, int right) {int center = (left + right) / 2;if (nums[left] > nums[center])swap(nums, left, center);//此时center大于leftif (nums[left] > nums[right])swap(nums, left, right);//此时left为最小if (nums[center] > nums[right])swap(nums, center, right);//把center值放到right-1的位置swap(nums, center, right - 1);return nums[right - 1];}public void quickSort2(int[] nums, int left, int right) {//cutoff为截断值if (left + CUTOFF <= right) {int pivot = median(nums, left, right);//随机值生成indexint l = left+1, r = right - 2;while (true) {while (nums[l] < pivot) {//找到第一个比pivot大的数l++;}while (nums[r] > pivot) {//r--;}if (l < r)swap(nums, l++, r--);elsebreak;}swap(nums, l, right-1);quickSort2(nums, left, l - 1);quickSort2(nums, l + 1, right);} else {insertSort(nums, left, right);}}public void insertSort(int[] nums, int left, int right) {int j;for (int i = left; i <= right; ++i) {int temp = nums[i];//寻找插入的位置for (j = i; j > left && temp < nums[j - 1]; j--) {nums[j] = nums[j - 1];}nums[j] = temp;}}public void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
2.快速选择
1.基本介绍
快速选择算法其实是快速排序算法的变形,主要用于解决寻找第k大元素或者第k小元素,当我们需要寻找找到(排序后)第k个元素的时候,不要求数组的所有元素必须有序,这个时候我们可以选择使用快速选择算法,因为快速选择算法的时间复杂度比直接使用快速排序的时间复杂度低
快速选择的时间复杂度:O(n)
快速排序的时间复杂度:O(nlog(n))
①中轴值最终能交换到第k个位置,说明我们找到了第k个元素

②中轴值最终的位置大于第k个位置,此时我们只需要对中轴值左边的元素进行快速排序

③中轴值最终的位置小于第k个位置,此时我们只需要对中轴值右边的元素进行快速排序

2.基本思路
快速选择的基本思路和快速排序算法还是一样的,无非就是多加了一个判断,判断是对中轴值左边进行快速排序,还是右边进行.
3.代码实现
1.随机值分割
public void quickSelect(int[] nums, int left, int right, int k) {if (left >= right)return;int index = (int) (left + Math.random() * (right - left + 1));int pivot = nums[index];//随机值生成indexswap(nums, index, right);int l = left, r = right - 1;while (true) {while (l < right && nums[l] < pivot) {//找到第一个比pivot大的数l++;}while (r > 0 && nums[r] > pivot) {//r--;}if (l < r)swap(nums, l++, r--);elsebreak;}swap(nums, l, right);if (l > k) {quickSelect(nums, left, l - 1, k);} else if (l < k) {quickSelect(nums, l + 1, right, k);}}
2.三数中值分割法
public static final int CUTOFF = 10;public int median(int[] nums, int left, int right) {int center = (left + right) / 2;if (nums[left] > nums[center])swap(nums, left, center);//此时center大于leftif (nums[left] > nums[right])swap(nums, left, right);//此时left为最小if (nums[center] > nums[right])swap(nums, center, right);//把center值放到right-1的位置swap(nums, center, right - 1);return nums[right - 1];}public void quickSelect2(int[] nums, int left, int right, int k) {if (left + CUTOFF <= right) {int pivot = median(nums, left, right);int l = left + 1, r = right - 2;while (true) {while (l < right && nums[l] < pivot) {//找到第一个比pivot大的数l++;}while (r > 0 && nums[r] > pivot) {//r--;}if (l < r)swap(nums, l++, r--);elsebreak;}swap(nums, l, right - 1);if (l > k) {quickSelect2(nums, left, l - 1, k);} else if (l < k) {quickSelect2(nums, l + 1, right, k);}} else {insertSort(nums, left, right);}}public void insertSort(int[] nums, int left, int right) {int j;for (int i = left; i <= right; ++i) {int temp = nums[i];//寻找插入的位置for (j = i; j > left && temp < nums[j - 1]; j--) {nums[j] = nums[j - 1];}nums[j] = temp;}}public void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
3.数组中的第K个最大元素
1.题目描述
给定整数数组
nums和整数k,请返回数组中第k个最大的元素。请注意,你需要找的是数组排序后的第
k个最大的元素,而不是第k个不同的元素。你必须设计并实现时间复杂度为
O(n)的算法解决此问题。
力扣:力扣
2.思路分析
看到题目我们就可以想到这一题可以使用快速选择算法肯定会更加高效,寻找第k个最大的元素,也就是寻找到nums.length-k个元素是什么即可,当然我们也可以直接快速排序,直接返回nums.length-k个元素
3.代码实现
1.直接使用快速排序
public int findKthLargest(int[] nums, int k) {quickSort(nums, 0, nums.length - 1);return nums[nums.length - k];}public void quickSort(int[] nums, int left, int right) {if (left >= right)return;int index = (int) (left + Math.random() * (right - left + 1));int pivot = nums[index];//随机值生成indexswap(nums, index, right);int l = left, r = right - 1;while (true) {while (l < right && nums[l] < pivot) {//找到第一个比pivot大的数l++;}while (r > 0 && nums[r] > pivot) {//r--;}if (l < r)swap(nums, l++, r--);elsebreak;}swap(nums, l, right);quickSort(nums, left, l - 1);quickSort(nums, l + 1, right);}public void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
2.快速选择
public int findKthLargest(int[] nums, int k) {quickSelect(nums, 0, nums.length - 1,nums.length-k);return nums[nums.length - k];}public void quickSelect(int[] nums, int left, int right, int k) {if (left >= right)return;int index = (int) (left + Math.random() * (right - left + 1));int pivot = nums[index];//随机值生成indexswap(nums, index, right);int l = left, r = right - 1;while (true) {while (l < right && nums[l] < pivot) {//找到第一个比pivot大的数l++;}while (r > 0 && nums[r] > pivot) {//r--;}if (l < r)swap(nums, l++, r--);elsebreak;}swap(nums, l, right);if (l > k ) {quickSelect(nums, left, l - 1,k);} else if (l < k ) {quickSelect(nums, l + 1, right,k);}}public void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
4.数组中的第K个最大元素
1.题目描述
给你一个二维矩阵
matrix和一个整数k,矩阵大小为m x n由非负整数组成。矩阵中坐标
(a, b)的 值 可由对所有满足0 <= i <= a < m且0 <= j <= b < n的元素matrix[i][j](下标从 0 开始计数)执行异或运算得到。请你找出
matrix的所有坐标中第k大的值(k的值从 1 开始计数)。
力扣:力扣
2.思路分析
这一题首先需要解决的就是将所有坐标的异或运算的结果表达出来,然后用一个ArrayList存起来,然后这个时候我们就可以使用快速选择求出来第k大的值了.
首先我们需要解决的就是各个位置的异或结果的值,一想到异或,并且题目中明确表达出 满足0 <= i <= a < m 且 0 <= j <= b < n 的元素 matrix[i][j],这个时候我们可以想到使用异或前缀和进行解答,我们这个时候需要找到进行递推的异或表达式
借用力扣官方题解的一幅图片,我们可以看出来异或递推公式为
prefix[i][j] = prefix[i - 1][j] ^ prefix[i][j - 1] ^ prefix[i - 1][j - 1] ^ matrix[i - 1][j - 1];

但我们我们看出(i,j)需要上一层的元素进行递推得到,如果我们定义的前缀异或的表达式长度为二维数组的大小的话,这个时候我们需要对第一行和第一列进行初始化,这个时候是很麻烦的,这个时候我们不妨定义的长度为m+1和n+1,刚开始元素的值都为1,并且一个值异或0还是本身,正好符合本题的意思
接下来进行快速选择,和上一题一样
3.代码实现
1.直接使用快速排序
public int kthLargestValue(int[][] matrix, int k) {int m = matrix.length;int n = matrix[0].length;int[][] prefix = new int[m + 1][n + 1];ArrayList<Integer> list = new ArrayList<>();for (int i = 1; i <= m; ++i) {for (int j = 1; j <= n; ++j) {prefix[i][j] = prefix[i - 1][j] ^ prefix[i][j - 1] ^ prefix[i - 1][j - 1] ^ matrix[i-1][j-1];list.add(prefix[i][j]);}}quickSort(list, 0, list.size() - 1);return list.get(list.size() - k);}public void quickSort(List<Integer> list, int left, int right) {if (left >= right)return;int index = (int) (left + Math.random() * (right - left + 1));int pivot = list.get(index);//随机值生成indexswap(list, index, right);int l = left, r = right - 1;while (true) {while (l < right && list.get(l) < pivot) {//找到第一个比pivot大的数l++;}while (r > 0 && list.get(r) > pivot) {//r--;}if (l < r)swap(list, l++, r--);elsebreak;}swap(list, l, right);quickSort(list, left, l - 1);quickSort(list, l + 1, right);}public void swap(List<Integer> list, int i, int j) {int temp = list.get(i);list.set(i, list.get(j));list.set(j, temp);}
2.快速选择
public int kthLargestValue(int[][] matrix, int k) {int m = matrix.length;int n = matrix[0].length;int[][] prefix = new int[m + 1][n + 1];ArrayList<Integer> list = new ArrayList<>();for (int i = 1; i <= m; ++i) {for (int j = 1; j <= n; ++j) {prefix[i][j] = prefix[i - 1][j] ^ prefix[i][j - 1] ^ prefix[i - 1][j - 1] ^ matrix[i-1][j-1];list.add(prefix[i][j]);}}quickSelect(list, 0, list.size() - 1, list.size() - k);return list.get(list.size() - k);}public void quickSelect(List<Integer> list, int left, int right, int k) {if (left >= right)return;int index = (int) (left + Math.random() * (right - left + 1));int pivot = list.get(index);//随机值生成indexswap(list, index, right);int l = left, r = right - 1;while (true) {while (l < right && list.get(l) < pivot) {//找到第一个比pivot大的数l++;}while (r > 0 && list.get(r) > pivot) {//r--;}if (l < r)swap(list, l++, r--);elsebreak;}swap(list, l, right);if (l > k) {quickSelect(list, left, l - 1, k);} else if (l < k) {quickSelect(list, l + 1, right, k);}}public void swap(List<Integer> list, int i, int j) {int temp = list.get(i);list.set(i, list.get(j));list.set(j, temp);}
相关文章:
快速排序/快速选择算法
一.快速排序 1.基本介绍 快速排序(Quicksort〉是对冒泡排序的一种改进,都属于交换排序。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分(每次选择中轴值),中轴值左边的元素小于中轴值,中轴值右边的元素全部大于中轴值(但不要求有序)&#x…...
【数据结构初阶】单链表面试题|内含链表带环问题
目录 前言 链表面试题 1. 删除链表中等于给定值 val 的所有节点。oj链接 2.反转一个单链表。oj链接 3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。oj链接 4. 输入一个链表,…...
一文解析ethtool 命令的使用
命令简介 ethtool命令用于查询和控制网络设备驱动程序和硬件设置,尤其是有线以太网设备,devname网卡的名称。网卡就像是交换机的一个端口,正常使用我们只是配置网卡IP地址等信息,网卡的速率、双工模式等我们并不关心。通过ethtoo…...
深度学习训练营之yolov5训练自己的数据集
深度学习训练营之训练自己的数据集原文链接环境介绍准备好数据集划分数据集运行voc_train.py遇到问题完整代码创建new_data.yaml文件模型训练时遇到的报错模型训练结果可视化参考链接原文链接 🍨 本文为🔗365天深度学习训练营 中的学习记录博客…...
Java中的AQS
文章目录什么是AQSAbstractQueuedSynchronizer方法解析自旋与阻塞ReentrantLock,Semaphore以及CountDownLatch对比ReentrantLock实现原理原理ReentrantLock源码中compareAndSetState的方法Semaphore实现原理CountDownLatch实现原理什么是AQS AQS是Java中的一个抽象…...
Spring——案例-业务层接口执行效率和AOP通知获取数据+AOP总结
执行时间获取:记录开始时间和结束时间,取差值。 这里使用环绕通知来实现。 环境准备: 项目文件结构: 业务层接口和实现类: 数据层: 采用mybatis注解开发,这里没有实现类,直接在接口方法里面实现映射。 domain层: 实现了数据库里面每一个…...
国外SEO舆情处理最佳黄金时间
在国外市场,SEO(搜索引擎优化)的舆情处理是非常重要的,因为它可以帮助提高网站的排名和流量,并且建立品牌的声誉和信誉。 然而,在什么时间进行舆情处理是一个值得探讨的问题。 在本文中,我们将…...
ROC和AUC
目录 ROC AUC ROC ROC曲线是Receiver Operating Characteristic Curve的简称,中文名为"受试者工作特征曲线"。ROC曲线的横坐标为假阳性率(False Postive Rate, FPR);纵坐标为真阳性率(True Positive Rate, TPR).FPR和TPR的计算方法分别为 F…...
Dopamine-PEG-cRGD,DOPA-PEG-cRGD,多巴胺-聚乙二醇-crgd细胞穿膜肽
名称:多巴胺-聚乙二醇-cRGD穿膜肽,多巴胺-聚乙二醇-crgd细胞穿膜肽英文名称:Dopamine-PEG-cRGD,DOPA-PEG-cRGD规格:50mg,100mg,150mg(根据要求可定制)描述:cRGD多肽序列: cyclo(RGDfK)外 观 : 半固体或固体,取决于分子量。溶解性:…...
动态规划回文子串
647. 回文子串方法:双指针回文子串有长度为奇数和偶数两种,extend(s, i, i, n); extend(s, i, i 1, n);就分别对应长度为奇数和偶数的情况class Solution { private:int extend(const string& s, int i, int j, int n) {int res 0;while (i > 0…...
windows 域控提权CVE-2014-6324CVE-2020-1472CVE-2021-42287CVE-2022-26923
一、CVE-2014-6324复现 环境:god.org域,两台主机,一台win2008域控,另一台web服务器win2008 工具:ms14-068.exe(漏洞exp) mimikatz psexec 利用条件: 1.域用户账号密码 2.获得一台主机权限(本地administ…...
1、JDK 安装 Java环境变量配置
jdk下载(Java8) (下载时间不同,小版本号会有变化,不影响后续安装) 官网下载地址:https://www.oracle.com/java/technologies/downloads/#java8-windows 下载完后安装 JDK 环境变量配置 Win…...
[c++]list模拟实现
目录 前言: 学习类的方式: 1 类成员变量 1.1 list成员变量 1.2 结点结构体变量 1.3 迭代器成员变量 2 默认函数——构造 2.1 结点结构体构造函数 2.2 list构造函数 2.3 迭代器构造函数 3 迭代器实现 3.1 list部分 3.2 迭代器结构体部分 3.2…...
实用的仓库管理软件有哪些,盘点2023年5大仓库管理软件!
对于做批发生意的老板或工厂老板来说,选择一款实用的仓库管理软件是至关重要的。仓库管理软件除了可以帮你降低仓库管理成本,提高经营管理的效率,还能够在手机上随时随地掌控仓库员工和商品的最新信息,与客户、供应商的订单情况能…...
(八十二)透彻研究通过explain命令得到的SQL执行计划(1)
今天我们正式进入研究explain命令得到的SQL执行计划的内容了,只要把explain分析得到的SQL执行计划都研究透彻,完全能看懂,知道每个执行计划在底层是怎么执行的,那么后面学习SQL语句的调优就非常容易了。 首先,我们现在…...
【Linux】旋转锁 | 读写锁
在之前的线程学习中,用到的锁都是挂起等待锁,如果申请不到锁,那就会在锁中等待; 自旋锁则不大相似 文章目录1.自旋锁1.1 概念1.2 接口1.2.1 pthread_spin_init/destroy1.2.2 pthread_spin_lock1.2.3 pthread_spin_unlock2.读写锁…...
EasyExcell导出excel添加水印
EasyExcell导出excel添加水印1、添加easyExcel相关依赖2、准备基础工具类3、创建水印handler类4、创建单元测试类WriteTest.class5、测试结果1、添加easyExcel相关依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId&…...
SpringCloud:Nacos配置管理
Nacos除了可以做注册中心,同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理…...
正则表达式引擎NFA自动机的回溯解决方案总结
前几天线上一个项目监控信息突然报告异常,上到机器上后查看相关资源的使用情况,发现 CPU 利用率将近 100%。通过 Java 自带的线程 Dump 工具,我们导出了出问题的堆栈信息。 我们可以看到所有的堆栈都指向了一个名为 validateUrl 的方法&#…...
卷积神经网络之AlexNet
目录概述AlexNet特点激活函数sigmoid激活函数ReLu激活函数数据增强层叠池化局部相应归一化DropoutAlexnet网络结构网络结构分析AlexNet各层参数及其数量模型框架形状结构关于数据集训练学习keras代码示例概述 由于受到计算机性能的影响,虽然LeNet在图像分类中取得了…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
