快速排序/快速选择算法
一.快速排序
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在图像分类中取得了…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
