这只是核心的算法,当然还存在一些优化的做法,但都是基于以下算法拓展的。 1 package com.meession.javaDataStruct.QuickSort; 2 3 /** 4 * 快排算法思想: 5 * 基于冒泡排序,对其改进,采用递归实现。 数组分区:此趟递归带排序的数组; 6 * 对于每一次的函数调用, 7 * i都被设置为从该数组分区的第0个元素开始,j从该数组分区的最后一个元素开始。 8 * (因为在QuickSort方法中,我们看到的是第一步方法递归之前的代码执行过程, 9 * 而第一步方法递归之前的数组分区是整个被待排序的数组, 10 * 所以在第一步递归之前i从整个数组的第0个元素开始,j从整个数组的最后一个元素开始) 11 * 并设置一个参照点。(理论上可以是该数组分区里面的任何值, 12 * 但由于在递归过程中数组长度的不确定性,导致容易出现数组越界的异常出现。 13 * 因此用该数组分区的第0个元素作为整个分区的参照点,以规避数组越界的异常发生)。 14 * 15 * 在找比参照点大和比参照点小的数据的时候不让i比j先执行循环的原因是: 16 * 一开始参照点被设置在了最左边,若按循环条件去寻找比参照点大的元素, 17 * 分隔数据的目的将无法达到。 18 * ^_^只有改变循环的条件才能做到i比j先执行循环又达到分隔数据的效果^_^。 19 * 20 * 在第一次递归之前的操作和原理弄明白之后,接下来就是递归的过程。 21 * 递归可以这么理解:你所使用的这个方法是别人已经给你写好的, 22 * 你只需使用它来完成你要实现的功能即可。 23 * 比如下面的sort函数的递归,你可以理解成:sun公司已经给你写好了这个方法, 24 * 它的参数就是这些:int[] arrs,int left,int right; 25 * 你需要实现的功能是:把参照点左边的数组分区和右边的数组分区的数据有序排好即可。 26 * 但在一开始自己编写这个方法的时候肯定不能这么理解, 27 * 不然我们就真的可以直接调用sun公司写好的快排方法了。 28 * 以上辅助理解的方式只是为了不要因为递归而把自己陷进头大般的痛苦之中。 29 * 简单来说,就是这么理解:你只需完成过程前的第一步操作, 30 * 接下了的操作就是自己调用已有的方法完成。两步加在一起,整个排序就完成了。 31 * 当然,递归肯定要有结束条件,就是:当数组分区的元素只有一个时, 32 * 即数组分区的最左边等于最右边等于键值的所在位置是时,对于每一个数组分区而言, 33 * 都是有序的。整个待排序数组也就成了有序的了。 34 * 35 * ************************************************************ 36 * 这只是快排的核心算法,若在某些地方改进,快排的执行效率会更高。 37 * 38 * 优点:排序的平均速度快(顾名思义嘛),计算机执行效率高 39 * 缺点:排序结果不稳定。也就是说,如果数组中存在n个大小相同的元素, 40 * 排序之后这n个元素的位置可能发生变化。即如果原来的序列是:n1、n2、n3、n4, 41 * 排序之后的序列可能变为:n2、n1、n4、n3 42 * 43 * 它的时间复杂度 最好O(NlogN),最坏O(N^2),平均O(NlogN) 44 * 空间复杂度:最好O(logN),最坏O(N),平均:O(logN) 45 * @author fzh 46 * 47 */ 48 public class QuickSort { 49 public void sort(int[] arrs,int left,int right){ 50 /** 51 * i从数组分区的第0个元素开始,j从数组分区的最后一个元素开始 52 * key为数组分割参照点。为防止数组越界异常出现,初始化key为数组分区的第0个元素 53 */ 54 int i = left; 55 int j = right; 56 int key = arrs[left]; 57 /** 58 * 用于交换数据的临时变量 59 */ 60 int temp; 61 /** 62 * 循环结束条件必为:i==j 63 */ 64 while(i<j){ 65 /** 66 * 当扫描数组分区的下标比待分隔区间(即参照点所在的区间的子区间, 67 * 这个区间左边元素全部小于参照点,右边的元素全部大于参照点。 68 * 而在这个区间的元素和参照点的大小关系还不确定)的最左边元素的下标大 69 * 且最左边元素后面的数据比参照点大的时候,下面这个循环满足循环条件, 70 * j减一,继续执行循环去找下标比i(分隔区间的最左边数据的下标)大、 71 * 数值比参照点小的数据,然后做交换 72 */ 73 while(j>i&&arrs[j]>=key)j--; 74 if(j>i){ 75 temp = arrs[j]; 76 arrs[j] = arrs[i]; 77 arrs[i] = arrs[j]; 78 } 79 80 /** 81 * 当扫描数组分区的下标比待分隔区间的最左边元素的下标大 82 * 且待分隔区间的最左边元素后面的数据比参照点小的时候,下面这个循环满足循环条件, 83 * i加1,继续执行循环去找下标比j(分隔区间的最右边数据的下标)小、 84 * 数值比参照点大的数据,然后做交换 85 */ 86 while(i<j&&arrs[i]<=key)i++; 87 if(i<j){ 88 temp = arrs[j]; 89 arrs[j] = arrs[i]; 90 arrs[i] = temp; 91 } 92 93 } 94 if(i>left)sort(arrs, left, i-1); 95 if(j<right)sort(arrs, j+1, right); 96 } 97 }
时间: 2024-10-07 13:33:28