热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

快速排序/快速选择算法

一.快速排序
一.快速排序

1.基本介绍

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

2.基本思路

我们每次选择一个中轴值,将中轴值和最后一个元素交换位置,对left到right-1的元素进行交换,当r<&#61;l,此时l停留到的位置和right位置上的元素(中轴值)进行交换,这个时候,l停留的位置上是中轴值,并且左边的元素比中轴值小,右边的元素比中轴值大,然后递归对左边和右边的元素进行快速排序,直到left>&#61;right的时候停止,此时数组便是有序的了.

1.关于中轴值的选择

大部分的可能给出的是选择第一个元素作为中轴值,但是这种做法有一定的弊端,如果是数组的元素是随机排序的,是可以接受的,但是如果数组的元素是预排序或者反序的,这样所有的元素不是全被划入到中轴值左边,就是划入到中轴值右边,那么时间复杂度就会很高

一种有效的方法时是采用随机产生一个下标为[left,right]的下标,这种情况下虽然可能会产生上面描述的情况,但总的来说可能性还是很小的.

还有一种方法是:三数中值分割法,我们选取三个数,使得三个数的最大值作为中轴值进行分割,一般来说我们选取左端,中端,右端的三个元素的终止作为中轴值,这种选取的方法还是

2.小数组情形

对于很小的数组(数组元素个数小于20),快速排序不如插入排序,因为快速排序是递归的.我们通常的做法是对于小的数组采用插入排序,一种好的截止范围是n&#61;10,同时这种做法也避免了三数中值分割法的错误情况,比如最终数组的元素只有一个元素或者两个元素,而无法三数分割

3.时间复杂度

快速排序的平均时间复杂度:O(nlogn) 

最好情况:O(nlogn) 

最坏情况:O(n^{2}

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

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

2.基本思路

快速选择的基本思路和快速排序算法还是一样的,无非就是多加了一个判断,判断是对中轴值左边进行快速排序,还是右边进行.

3.代码实现


1.随机值分割

public void quickSelect(int[] nums, int left, int right, int k) {if (left >&#61; right)return;int index &#61; (int) (left &#43; Math.random() * (right - left &#43; 1));int pivot &#61; nums[index];//随机值生成indexswap(nums, index, right);int l &#61; left, r &#61; right - 1;while (true) {while (l 0 && nums[r] > pivot) {//r--;}if (l k) {quickSelect(nums, left, l - 1, k);} else if (l

2.三数中值分割法

public static final int CUTOFF &#61; 10;public int median(int[] nums, int left, int right) {int center &#61; (left &#43; 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 &#43; CUTOFF <&#61; right) {int pivot &#61; median(nums, left, right);int l &#61; left &#43; 1, r &#61; right - 2;while (true) {while (l 0 && nums[r] > pivot) {//r--;}if (l k) {quickSelect2(nums, left, l - 1, k);} else if (l left && temp

3.数组中的第K个最大元素

1.题目描述


给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。

请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 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 >&#61; right)return;int index &#61; (int) (left &#43; Math.random() * (right - left &#43; 1));int pivot &#61; nums[index];//随机值生成indexswap(nums, index, right);int l &#61; left, r &#61; right - 1;while (true) {while (l 0 && nums[r] > pivot) {//r--;}if (l

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 >&#61; right)return;int index &#61; (int) (left &#43; Math.random() * (right - left &#43; 1));int pivot &#61; nums[index];//随机值生成indexswap(nums, index, right);int l &#61; left, r &#61; right - 1;while (true) {while (l 0 && nums[r] > pivot) {//r--;}if (l k ) {quickSelect(nums, left, l - 1,k);} else if (l

4.数组中的第K个最大元素

1.题目描述


给你一个二维矩阵 matrix 和一个整数 k &#xff0c;矩阵大小为 m x n 由非负整数组成。

矩阵中坐标 (a, b) 可由对所有满足 0 <&#61; i <&#61; a 0 <&#61; j <&#61; b 的元素 matrix[i][j]&#xff08;下标从 0 开始计数&#xff09;执行异或运算得到。

请你找出 matrix 的所有坐标中第 k 大的值&#xff08;k 的值从 1 开始计数&#xff09;。

力扣:力扣

2.思路分析

这一题首先需要解决的就是将所有坐标的异或运算的结果表达出来,然后用一个ArrayList存起来,然后这个时候我们就可以使用快速选择求出来第k大的值了.

首先我们需要解决的就是各个位置的异或结果的值,一想到异或,并且题目中明确表达出 满足0 <&#61; i <&#61; a 0 <&#61; j <&#61; b 的元素 matrix[i][j],这个时候我们可以想到使用异或前缀和进行解答,我们这个时候需要找到进行递推的异或表达式

借用力扣官方题解的一幅图片,我们可以看出来异或递推公式为

prefix[i][j] &#61; prefix[i - 1][j] ^ prefix[i][j - 1] ^ prefix[i - 1][j - 1] ^ matrix[i - 1][j - 1];

但我们我们看出(i,j)需要上一层的元素进行递推得到,如果我们定义的前缀异或的表达式长度为二维数组的大小的话,这个时候我们需要对第一行和第一列进行初始化,这个时候是很麻烦的,这个时候我们不妨定义的长度为m&#43;1和n&#43;1,刚开始元素的值都为1,并且一个值异或0还是本身,正好符合本题的意思

接下来进行快速选择,和上一题一样

3.代码实现


1.直接使用快速排序

public int kthLargestValue(int[][] matrix, int k) {int m &#61; matrix.length;int n &#61; matrix[0].length;int[][] prefix &#61; new int[m &#43; 1][n &#43; 1];ArrayList list &#61; new ArrayList<>();for (int i &#61; 1; i <&#61; m; &#43;&#43;i) {for (int j &#61; 1; j <&#61; n; &#43;&#43;j) {prefix[i][j] &#61; 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 list, int left, int right) {if (left >&#61; right)return;int index &#61; (int) (left &#43; Math.random() * (right - left &#43; 1));int pivot &#61; list.get(index);//随机值生成indexswap(list, index, right);int l &#61; left, r &#61; right - 1;while (true) {while (l 0 && list.get(r) > pivot) {//r--;}if (l list, int i, int j) {int temp &#61; list.get(i);list.set(i, list.get(j));list.set(j, temp);}

2.快速选择

public int kthLargestValue(int[][] matrix, int k) {int m &#61; matrix.length;int n &#61; matrix[0].length;int[][] prefix &#61; new int[m &#43; 1][n &#43; 1];ArrayList list &#61; new ArrayList<>();for (int i &#61; 1; i <&#61; m; &#43;&#43;i) {for (int j &#61; 1; j <&#61; n; &#43;&#43;j) {prefix[i][j] &#61; 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 list, int left, int right, int k) {if (left >&#61; right)return;int index &#61; (int) (left &#43; Math.random() * (right - left &#43; 1));int pivot &#61; list.get(index);//随机值生成indexswap(list, index, right);int l &#61; left, r &#61; right - 1;while (true) {while (l 0 && list.get(r) > pivot) {//r--;}if (l k) {quickSelect(list, left, l - 1, k);} else if (l list, int i, int j) {int temp &#61; list.get(i);list.set(i, list.get(j));list.set(j, temp);}


推荐阅读
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • Java学习笔记之使用反射+泛型构建通用DAO
    本文介绍了使用反射和泛型构建通用DAO的方法,通过减少代码冗余度来提高开发效率。通过示例说明了如何使用反射和泛型来实现对不同表的相同操作,从而避免重复编写相似的代码。该方法可以在Java学习中起到较大的帮助作用。 ... [详细]
  • 本文介绍了解决Facebook脸书面试题中插入区间的方法,通过模拟遍历的方式判断当前元素与要插入元素的关系,找到插入点并将新区间插入。同时对算法的时间复杂度和空间复杂度进行了分析。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • Givenasinglylinkedlist,returnarandomnode'svaluefromthelinkedlist.Eachnodemusthavethe s ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
author-avatar
云淡风轻轻00
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有