Java实现快速排序过程分析

快速排序过程

没有既不浪费空间又可以快一点的排序算法呢?那就是“快速排序”!光听这个名字是不是就觉得很高端呢。

假设我们现在对“52 39 67 95 70 8 25 52'”这个8个数进行排序。首先在这个序列中随便找一个数作为基准数(不要被这个名词吓到了,就是一个用来参照的数,待会你就知道它用来做啥的了)。为了方便,就让第一个数70作为基准数吧。接下来,需要将这个序列中所有比基准数大的数放在70的右边,比基准数小的数放在70的左边,类似下面这种排列:

8 25 39 52 52' 67 70 95

在初始状态下,数字70在序列的第5位。我们的目标是将70挪到序列中间的某个位置,假设这个位置是k。现在就需要寻找这个k,并且以第k位为分界点,左边的数都小于等于70,右边的数都大于等于70。想一想,你有办法可以做到这点吗?

基本思想是分治的思想,说到分治,就应该想到和递归是分不开的。

有些书上会使用关键字比较的表述,有些书上会直接使用记录比较表述,这两种说法是两个维度上的说法。这里序列元素的关键字属于记录的一部分,为了简化问题,本文的讨论并不区分关键字和记录,代码实现中使用整数来表示记录。简而言之,本文的讨论简化为,对整型数组的快速排序。

通过一趟排序将要排序的记录分割成两部分,一部分的关键字值比别一部分的所有关键字都小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中所有记录都是有序为止。

步骤

1)分解。选择第一个元素作为基准数,将输入序列array[m…n]划分成两个非空序列array[m…k]和array[k+1…n],使array[m…k]中任一元素的值不大于array[k+1…n]任一元素值。

2)递归求解。通过递归调用快排算法分别对array[m…k]和array[k+1…n]进行排序

3)合并。由于对分解出的两个子序列排序都是原地进行的,所以在array[m…k]和array[k+1…n]都排好序后不需要再执行任何计算,就能将array[m…n]排好序。因此这一步是不需要在程序中体现的。

排序过程分析

初始关键字:52 39 67 95 70 8 25 52' ,下面将列出每一趟执行的结果。

基准52: 52 39 67 95 70 8 25 52'

基准25: 8 25 39 52 70 95 67 52‘

基准70: 8 25 39 52 52' 67 70 95

基准52‘:8 25 39 52 52' 67 70 95

算法分析

快速排序的时间复杂度与关键字初始序列有关。

最坏时间复杂度:O(n^2):

以第一个数或最后一个数为基准时,当初始序列整体或局部有序时,快速排序的性能会下降。若整体有序,此时,每次划分只能分出一个元素,具有最坏时间复杂度,快速排序将退化成冒泡排序。

最好时间复杂度:

每次选取的基准关键字都是待排序列的中间值,也就是说每次划分可以将序列划分为长度相等的两个序列。快速排序的递归过程可以用一棵二叉树来表示,递归树的高度是2为底的对数,每层需要比较的次数是n/2,所以最好时间复杂度是O(n*以2为底n的对数),因为很多时候输入序列都是乱序的,所以最好时间复杂度也是平均时间复杂度。

三种快排和四种优化方法

三种快排

这里区分的方式是不同基准的选择方法:

1)固定位置,取第一个或最后一个元素作为基准。这种选取方法不合适局部有序的输入。

2)随机选取基准,利用随机算法,选取待排序序列中任意一个元素作为基准。

3)三数取中,取数列中第一个数,中间位置的数,最后一个数作一个平均值作为基准。

四种优化

1)当排序序列长度分割到一定程度时,使用插入排序

对于N很小或局部有序的数组,直接插入排序的效率非常高。

2)在一次分割结束后,可以把与基准数相等的元素聚在一起,下次分割时忽略掉这些元素。

对于含有重复元素比较多的序列,这种优化方法效果比较好,可以减少很多跌代次数。

具本过程:

第一步:在划分过程,把与所选取的基准数相等的元素放在数组的两端。

第二步:划分结束后,把两端的与基准数相等的元素移到基准数最终位置的两侧。

3)优化递归操作。

4)使用多线程并行处理子划分。

Partition方法在求TopK问题上的应用

TopK问题即求序列中最大或最小的K个数。这里以求最小K个数为例。

快速排序的思想是使用一个基准元素将数组划分成两部分,左侧都比基准数小,右侧都比基准数大。

给定数组array[low…high],一趟快排划分后的结果有三种:

1)如果基准数左侧元素个数Q刚好是K-1,那么在基准数左侧(包含基准数本身),即为TopK的所有元素。

2)如果基准数左侧元素个数Q小于K-1,那么说明基准数左侧的Q个数都是TopK里的元素,只需要在基准数的右侧找出剩下的K-Q个元素即可。问题转化成了以基准数下标为起点,高位(high)为终点的Top(K-Q)。递归下去即可。

3)如果基准数左侧元素个数Q大于K-1,说明第K个位置,在基准数的左侧,需要缩小搜索范围,在低位(low)至基准数位置重复递归即可,最终问题会转化成上面两种情况。

快排java实现

在手写快排算法时,最好先把一趟排序的过程写出来。

package sort;
public class QuickSort {
 // 暴露只一个参数的公共接口
 public void quickSort(int a[]) {
 sort(a, 0, a.length - 1);
 }
 // 快排算法的真正实现
 private void sort(int[] a, int low, int high) {
 if (low >= high)
 return;
 int i = low, j = high; // 设置这两个变量的目的是为了保持low和high不变
 int pivotNum = a[i]; // 基准数
 while (i < j) {
 while (a[j] >= pivotNum && j > i) { // 循环结束的条件有二:一是找到比支点小的数,二是j==i
 j--;
 }
 if (j > i) { // 由于上面循环结束的功能性有两个,对于找到比支点小的数,即j!=i,要进行位置的交换,下同
 a[i] = a[j];
 i++;
 }
 while (a[i] < pivotNum && i < j) {
 i++;
 }
 if (i < j) {
 a[j] = a[i];
 j--;
 }
 }
 a[i] = pivotNum;
 sort(a, low, i - 1);
 sort(a, i + 1, high);
 }
 public static void main(String[] args) {
 int[] a = { 52, 39, 67, 95, 70, 8, 25, 52 };
 new QuickSort().quickSort(a);
 for (int i : a) {
 System.out.print(i + " ");
 }
 }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • 快速排序的原理及java代码实现

    概述 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(nlogn)次比较.事实上,快速排序通常明显比其他Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,并且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性. 快速排序,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序的目的. 形象图示:

  • Java编程实现快速排序及优化代码详解

    普通快速排序 找一个基准值base,然后一趟排序后让base左边的数都小于base,base右边的数都大于等于base.再分为两个子数组的排序.如此递归下去. public class QuickSort { public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } public static <T extends Comparabl

  • Java编程中快速排序算法的实现及相关算法优化

    时间复杂度 平均情况:O(nlgn) 最坏情况:O(n*n),发生在当数据已经是排序状态时 快排算法的基本原理 1.从数据中选取一个值a[i]作为参考 2.以a[i] 为参考,将数据分成2部分:P1.P2,P1中的数据全部≤a[i],P2中的数据全部>a[i],数据变为{{P1}{a[i]}{P2}} 3.将P1.P2重复上述步骤,直到各部分中只剩1个数据 4.数据完成升序排列 基本示例: 原始数据: {3,9,8,5,2,1,6} 第1步:选取第1个数据:3 第2步:将数据分成2部分,左边≤3

  • Java 冒泡排序、快速排序实例代码

    冒泡排序 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地 进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端. 冒泡排序的算法实现如下:[排序后,数组从小到大排列] /** * 冒泡排序 * 比较相邻的元素.如果第一个比第二个大,就交换他们两个. * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应

  • Java基于分治法实现的快速排序算法示例

    本文实例讲述了Java基于分治法实现的快速排序算法.分享给大家供大家参考,具体如下: package cn.nwsuaf.quick; /** * 随机产生20个数,并对其进行快速排序 * * @author 刘永浪 * */ public class Quick { /** * 交换函数,实现数组中两个数的交换操作 * * @param array * 待操作数组 * @param i * 交换数组的第一个下标 * @param j * 交换数组的第二个下标 */ public static

  • 图文讲解Java中实现quickSort快速排序算法的方法

    相对冒泡排序.选择排序等算法而言,快速排序的具体算法原理及实现有一定的难度.为了更好地理解快速排序,我们仍然以举例说明的形式来详细描述快速排序的算法原理.在前面的排序算法中,我们以5名运动员的身高排序问题为例进行讲解,为了更好地体现快速排序的特点,这里我们再额外添加3名运动员.实例中的8名运动员及其身高信息详细如下(F.G.H为新增的运动员): A(181).B(169).C(187).D(172).E(163).F(191).G(189).H(182) 在前面的排序算法中,这些排序都是由教练主

  • java实现快速排序的方法

    本文实例讲述了java实现快速排序的方法.分享给大家供大家参考.具体实现方法如下: public class Quick { public static int[] Data = { 9, 8, 7, 4, 1, 12, 15, 63, 15, 20 }; public static void quick(int left, int right) { int i, j; int Pivot; int temp; i = left; j = right; Pivot = Data[(left+ri

  • java简单快速排序实例解析

    一.基本概念 找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置.递归快速排序,将其他n-1个元素也调整到排序后的正确位置.最后每个元素都是在排序后的正 确位置,排序完成.所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归. 二.选择基准元 1.固定基准元 如果输入序列是随机的,处理时间是可以接受的.如果数组已

  • java 算法之快速排序实现代码

    java 算法之快速排序实现代码 摘要: 常用算法之一的快速排序算法的java实现 原理:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描, 将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素, 此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分. /** * * @author 阿信sxq-2015年7月16日 * * @param args */ public static void main(String[] args) { int

  • 快速排序算法在Java中的实现

    快速排序的原理:选择一个关键值作为基准值.比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的).一般选择序列的第一个元素. 一次循环:从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换.找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,如果没有继续比较下一个,直到找到第一个比基准值大的值才交换.直到从前往后的比较索引>从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两

  • JAVA一个快速排序实现代码

    首先排序的方法有很多种:插入排序,冒泡排序,堆排序,归并排序,选择排序,计数排序,基数排序,桶排序,快速排序等 这里是主要讲解一下快速排序这个方法,我也是看了好几篇文章才看明白的: 1.先在待排序的一组数据中随便选一个数出来作为基数:key: 2.然后对这组数进行排序,比key小的放key的左边,比key大的放key的右边,当然这个按照需求来(从小到大,还是从大到小) 3.递归的来分组,在第二步中在将这个组数字,分成多个小组来排序就可以了 具体看代码来理解,可能会更加好理解 package co

  • 详解快速排序算法中的区间划分法及Java实现示例

    快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序.该方法的基本思想是: 1.先从数列中取出一个数作为基准数. 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边. 3.再对左右区间重复第二步,直到各区间只有一个数. 算法的思路很清晰,但是如果在区间划分过程中边界值没有处理好,也是很容易出现bug的.下面给出两种比较清晰的思维来指导区间划分代码的编写. 第一种思维即所谓的挖坑法思维,下面通过分析一个实例来分析一下挖坑法的过程: 以一个数组作为示例,取区间

  • 详解Java中使用泛型实现快速排序算法的方法

    快速排序算法概念 快速排序一般基于递归实现.其思路是这样的: 1.选定一个合适的值(理想情况中值最好,但实现中一般使用数组第一个值),称为"枢轴"(pivot). 2.基于这个值,将数组分为两部分,较小的分在左边,较大的分在右边. 3.可以肯定,如此一轮下来,这个枢轴的位置一定在最终位置上. 4.对两个子数组分别重复上述过程,直到每个数组只有一个元素. 5.排序完成. 基本实现方式: public static void quickSort(int[] arr){ qsort(arr,

随机推荐