分治法在排序算法中的应用(JAVA)--快速排序(Lomuto划分、Hoare划分、随机化快排)

分治法在排序算法中的应用--快速排序

时间复杂度:平均O(nlogn),最坏O(n^2)

如果说归并排序是按照元素在数组中的位置划分的话,那么快速排序就是按照元素的值进行划分。划分方法由两种,本节将主要介绍Huare划分,这也是我们通常采用的划分方法。

为了文章完整,下面只给出基于Lomuto划分的代码,详细分析请参考减治法在查找算法中的应用(JAVA)--快速查找

1、基于Lomuto划分的快速排序算法

public class Main {static int[] a= {5, 3, 1, 9, 8, 2, 4, 7};public static void main(String[] args) {fastsort(0, a.length-1);for (int i = 0; i < a.length; i++) {System.out.print(a[i] + " ");}}private static int Lomuto(int l, int r) {int p = a[l];int s = l;for (int i = l+1; i <= r; i++) {if (a[i] < p) {s = s+1;int temp = a[s];a[s] = a[i];a[i] = temp;}}int temp = a[l];a[l] = a[s];a[s] = temp;return s;}private static void fastsort(int l, int r) {if (l < r) {int s = Lomuto(l, r);fastsort(l, s-1);fastsort(s+1, r);}}
}

2、基于Hoare划分的快速排序算法

Hoare划分是一种更为复杂的划分方式,但是这也是在网上最为流行的一个划分方式。

我们假设有一个数组a[0, n-1],其子数组为a[l, r](0 <= l <= r <= n-1),假定首个元素为枢轴p,下面从数组两端进行扫描,并将扫描到的元素与枢轴比较。从左到右扫描(用指针i来表示),扫描到第一个大于等于枢轴p的,停止;从右到左扫描(用指针j表示,遇到第一个小于等于枢轴的元素)。这里注意等于枢轴的元素也要进行处理,这样可以保证数组分的更加平均。如果遇到相等元素继续扫描,对于一个具有n个相同元素的数组来说,划分后得到的两个子数组长度可能为n-1和0。

两侧的扫描都停止之后,根据扫描指针是否相交会有三种情况:若 i < j,则交换a[i]与a[j],i+1,j-1;若 i > j,交换a[p]与a[j];若i = j,则交换a[p]与a[j]。眼尖的读者估计看出来了,后两种情况其实是一种。

下图为Hoare划分的示意图:

public class Main {static int[] a= {5, 3, 1, 9, 8, 2, 4, 7};public static void main(String[] args) {fastsort(0, a.length-1);for (int i = 0; i < a.length; i++) {System.out.print(a[i] + " ");}}private static int Hoare(int l, int r) {int p = a[l];int i = l-1;int j = r+1 ;while (true) {do {j--;} while (a[j] > p);do {i++;} while (a[i] < p);if (i < j) {int temp = a[i];a[i] = a[j];a[j] = temp;} elsereturn j;}}private static void fastsort(int l, int r) {if (l < r) {int s = Hoare(l, r);fastsort(l, s);fastsort(s+1, r);}}
}

 

 

一般来说,如果我们要考虑一个算法的实用性,我们需要讨论的不是最坏情况下的效率,而应该是平均情况下的效率。实际经过分析,快速排序平均情况下的操作仅比最优情况多执行39%的比较过程而已。所以在处理随机序列时,速度要强于归并排序和堆排序。

缺点:快速排序并非稳定性排序方式,空间复杂度为O(logn),不及堆排序的空间复杂度O(1).

提出问题:对于数组非常小的情况下(对于大多数计算机来说,元素个数为5-15),使用插入排序会更快

解决思路1:判断元素个数,较小时采用插入排序,较大时采用快速排序。

解决思路2:不再对划分出来的较小数组排序,而是在快速排序结束后再使用插入排序的方法对整个接近有序的数组进行细微调节。

 

随机化快排:使用随机元素作为枢轴

提出问题:如果我们每次都选取第一个元素为枢轴,这自然会有诸多不便,不能应对一些特殊的情况。

解决思路:随机化快速排序、三平均划分法,下面给出代码,基本思想还是划分,有兴趣的读者可以研究一下。

public class Main {static int[] a= {5, 3, 1, 9, 8, 2, 4, 7};public static void main(String[] args) {fastsort(0, a.length-1);for (int i = 0; i < a.length; i++) {System.out.print(a[i] + " ");}}private static int random_partition(int l, int r) {int i = (int) (l + Math.random() % (r - l + 1));int temp = a[i];a[i] = a[r];a[r] = temp;return partition(l, r);}private static int partition(int l, int r) {int p = a[r];int i = l - 1;for (int j = l; j < r; j++) {if (a[j] <= p) {i++;int temp = a[i];a[i] = a[j];a[j] = temp;}}int temp = a[i+1];a[i+1] = a[r];a[r] = temp;return i+1;}private static void fastsort(int l, int r) {if (l < r) {int s = random_partition(l, r);random_partition(l, s-1);random_partition(s+1, r);}}
}

三平均划分法快排:以最左元素、最右元素、最中间元素的中位数为枢轴

public class Main {static int[] a= {5, 3, 1, 9, 8, 2, 4, 7};public static void main(String[] args) {fastsort(0, a.length-1);for (int i = 0; i < a.length; i++) {System.out.print(a[i] + " ");}}public static int mid_partition(int l, int r){int range = r - l + 1;int mid1 = (int) (l + Math.random() % range);int mid2 = (int) (l + Math.random() % range);int mid3 = (int) (l + Math.random() % range);int mid  = (a[mid1] < a[mid2]) ?(a[mid2] < a[mid3] ? mid2 : (a[mid1] < a[mid3] ? mid3 : mid1)):(a[mid1] < a[mid3] ? mid1 : (a[mid2] < a[mid3] ? mid2 : mid3));int temp = a[mid];a[mid] = a[r];a[r] = temp;return partition(l, r);}private static int partition(int l, int r) {int p = a[r];int i = l - 1;for (int j = l; j < r; j++) {if (a[j] <= p) {i++;int temp = a[i];a[i] = a[j];a[j] = temp;}}int temp = a[i+1];a[i+1] = a[r];a[r] = temp;return i+1;}private static void fastsort(int l, int r) {if (l < r) {int s = mid_partition(l, r);fastsort(l, s-1);fastsort(s+1, r);}}
}

提出问题:在划分方式上Lomuto划分和Hoare划分也可以进行改进,使用诸如三路划分的方式,将数组划分3段,每段元素分别小于、等于、大于枢轴元素等等。当然,这些就仅供研究学习了,平时我们使用最简单版本的快速排序是没有任何问题的。

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

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

相关文章

Excel中用REPT函数制作图表

本文从以下七个方面&#xff0c;阐述在Excel中用REPT函数制作图表&#xff1a; 一. 图形效果展示 二. REPT语法解释 三. REPT制作条形图 四. REPT制作漏斗图 五. REPT制作蝴蝶图 六. REPT制作柱状图 七. REPT制作甘特图 一. 图形效果展示 这些图表都是用REPT函数制作成的&#…

分治法在求解“最近对”问题中的应用(JAVA)

分治法在求解“最近对”问题中的应用 最近对问题在蛮力法中有过讲解&#xff0c;时间复杂度为O(n^2)&#xff0c;下面将会采用分治法讲解这类问题&#xff0c;时间复杂度会降到O(nlogn) 我们将笛卡尔平面上n>1个点构成的集合称为P。若2< n < 3时&#xff0c;我们1可…

【转】python的复制,深拷贝和浅拷贝的区别

在python中&#xff0c;对象赋值实际上是对象的引用。当创建一个对象&#xff0c;然后把它赋给另一个变量的时候&#xff0c;python并没有拷贝这个对象&#xff0c;而只是拷贝了这个对象的引用 一般有三种方法&#xff0c; alist[1,2,3,["a","b"]] &#x…

分治法在求解凸包问题中的应用(JAVA)--快包算法

分治法在求解凸包问题中的应用&#xff08;JAVA&#xff09; 之前写过一篇蛮力法在求解凸包问题中的应用&#xff08;JAVA&#xff09;还算简单易懂&#xff0c;没有基础的读者最好先去阅读以下。这里用分治法来求解凸包问题&#xff0c;由于这个算法和快速排序十分相似&#x…

动态规划在求解硬币问题中的应用(JAVA)--币制最大化、找零问题、硬币收集问题

动态规划&#xff1a;这种算法思想多用来求解最优化问题&#xff0c;因此这里存在一个最优化法则&#xff0c;法则指出最优化问题任一实例的最优解&#xff0c;都是由其子实例的最优解构成的。一般来说&#xff0c;自底向上的动态规划更容易设计&#xff0c;但是带有记忆功能的…

使用网络TCP搭建一个简单文件下载器

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 目录 一丶项目介绍 二丶服务器Server 三丶测试TCP server服务器 四丶客户端Client 五丶测试客户端向服务器下载文件 一丶项目介绍 1.叙述 生活中大家…

动态规划在求解背包问题中的应用(JAVA)--回溯法、记忆化法

动态规划在求解背包问题中的应用 背包问题向来是动态规划的典型问题&#xff0c;给定n个重量为w1,w2,...,wn&#xff0c;价值为v1,v2,...,vn的物品和一个称重量为W的背包&#xff0c;求这些物品中最优价值的一个子集&#xff0c;且能够装到背包中。 之前用蛮力法做过背包问题蛮…

JS跨域问题

因为浏览器的同源策略&#xff0c;默认情况下&#xff0c;JavaScript在发送AJAX请求时&#xff0c;URL的域名必须和当前页面完全一致。 完全一致的意思是&#xff0c;域名要相同&#xff08;www.example.com和example.com不同&#xff09;&#xff0c;协议要相同&#xff08;ht…

svn 服务器的搭建以及客户端的使用

1、svn 服务器的搭建以及客户端的使用&#xff0c;安装见下面的博客 https://blog.csdn.net/zh123456zh789/article/details/80921179 说明&#xff1a;服务器只是用来存储数据&#xff0c;服务器上的数据可以通过客户端torisesvn进行操作。比如将自己的项目存到服务器&#xf…

动态规划在求解传递闭包问题中的应用(JAVA)--Warshell算法

动态规划在求解传递闭包问题中的应用&#xff1a; 传递闭包&#xff1a;对于n个顶点有向图来说&#xff0c;如果第i个顶点到第j个顶点之间存在一条有效的有向路径&#xff08;即长度大于0的路径&#xff09;&#xff0c;那么T(i, j) 1,否则T(i, j) 0。例如&#xff1a;求解传…

Centos 7 LVM xfs文件系统修复

情况1&#xff1a; [sda] Assuming drive cache: write through Internal error xfs XFS_WANT_CORRUPTED_GOTO at line 1662 of file fs/xfs/libxfs/xfs_alloc.c Caller xfs_free_extent0x130 [xfs] Internal error xfs_trans_cancel at line 990 of file fs/xfs/xfs_trans.c.C…

动态规划在求解全源最短路径中的应用(JAVA)--Floyd算法

参考图论算法&#xff08;二&#xff09;-最短路径的Dijkstra [ 单源 ] 和Floyd[ 多源 ] 解法&#xff08;JAVA &#xff09;这种算法也叫Floyd-Warshell算法&#xff0c;虽然和Warshell算法名字相近&#xff0c;算法思想也相近&#xff0c;但确实是两种算法。对于一个带权图&a…

录播图的分页使用进度条形式显示

本次我是使用的slick轮播图插件&#xff0c;其官网网址如下&#xff1a; http://kenwheeler.github.io/slick/&#xff0c;下面是轮播图中的代码&#xff0c;如果你不知道效果是什么样子&#xff0c;亦可以去看一下阿里云的官网&#xff1a;https://www.aliyun.com/?utm_conte…

贪婪算法在求解最小生成树中的应用(JAVA)--Prim算法

贪婪算法&#xff1a;通过一系列步骤来构造问题的解&#xff0c;每一步对目前构造的部分分解做一个拓展&#xff0c;直到获得问题的完整解为止,而算法的核心思想就在于&#xff0c;算法的每一步都必须满足以下条件&#xff1a;可行&#xff08;满足问题的约束条件&#xff09;、…

贪婪算法在求解最小生成树中的应用(JAVA)--Kruskal算法

Kruskal算法又被称为“加边法”&#xff0c;这种算法会将加权连通图的最小生成树看成具有V-1条边的无环子图&#xff0c;且边的权重和最小。算法开始时&#xff0c;会按照权重的非递减顺序对图中的边排序&#xff0c;之后迭代的以贪婪的方式添加边。 下面以下图为例来讲解Krusk…

贪婪算法在求解最短路径中的应用(JAVA)--Dijkstra算法

最短路径问题最经典的算法就是Dijkstra算法&#xff0c;虽然不如Floyd算法能够求全源的最短路径&#xff0c;但是在效率上明显强于Floyd算法。 想了解Floyd算法的读者可以参考动态规划在求解全源最短路径中的应用&#xff08;JAVA&#xff09;--Floyd算法 单源最短路径问题是对…

贪婪算法在解决哈夫曼树及编码问题中的应用

哈夫曼编码&#xff0c;是一种可变字长编码(VLC)的高效算法。该算法是Huffman于1952年提出一种编码方法&#xff0c;该方法完全依据字符出现概率来构造异字头的平均长度最短的码字&#xff0c;有时称之为最佳编码。 相比定长编码来说&#xff0c;这种编码实现的压缩率&#xff…

素数筛法求十亿内所有质数的和(C++)

埃拉托斯特尼筛法&#xff08;又称埃氏筛&#xff09;的基本思想是&#xff1a;要得到自然数n以内的全部素数&#xff0c;必须把不大于的所有素数的倍数剔除&#xff0c;剩下的就是素数。 时间复杂度O(nloglogn) #include <iostream> #include <math.h> using na…

spring事务的传播机制新解

以下是事物的传播机制&#xff1a; Transactional(propagationPropagation.REQUIRED)如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)Transactional(propagationPropagation.NOT_SUPPORTED)容器不为这个方法开启事务Transactional(propagationPropagation.REQUIRES_NE…

时空权衡在模式匹配算法中的应用(JAVA)--Horspool算法(简化版BM算法)

模式匹配是数据结构中字符串的一种基本运算&#xff0c;给定一个子串&#xff0c;要求在某个字符串中找出与该子串相同的所有子串。假设P是给定的子串&#xff0c;T是待查找的字符串&#xff0c;要求从T中找出与P相同的所有子串&#xff0c;这个问题成为模式匹配问题。P称为模式…