快速排序也是一种分治算法。主要思想是选取一个切分点,将大于切分点的元素都放置到数组右侧,小于切分点的元素都放置到数组左侧;然后递归,再对切分点左侧和右侧分别排序。

归并排序时递归在前,归并在后,快速排序是切分在前,排序在后。

快速排序的运行时间在1.39nlogn的某个常数因子范围之内,归并排序也能做到这一点,但是快速排序更快,因为它的移动次数更少。

快速排序的关键点在于切分点的选取,对于正好逆序的情况,它的复杂度达到了n2,而且与归并排序相比不稳定。

为了防止最坏情况的出现,一般在排序前先将元素随机打乱。

  1. package 排序;
  2.  
  3. import edu.princeton.cs.algs4.In;
  4. import edu.princeton.cs.algs4.StdOut;
  5. import edu.princeton.cs.algs4.StdRandom;
  6. /**
  7. * @author evasean www.cnblogs.com/evasean/
  8. */
  9. @SuppressWarnings("rawtypes")
  10. public class Quick快速排序 {
  11. private static int partition(Comparable[] a, int lo, int hi){
  12. int i = lo;
  13. int j = hi+1;
  14. Comparable v = a[lo];//切分元素
  15. while(true){
  16. while(less(a[++i],v))
  17. if(i==hi) break;
  18. while(less(v,a[--j]))
  19. if(j==lo) break;
  20. if(i>=j) break;
  21. exch(a,i,j);
  22. }
  23. exch(a,lo,j);//此时j<=i,且v > a[j],将切分元素v放入正确位置
  24. return j;
  25. }
  26. public static void sort(Comparable[] a){
  27. StdRandom.shuffle(a); //消除最坏的情况
  28. sort(a,0,a.length-1);
  29. }
  30. private static void sort(Comparable[] a, int lo, int hi){
  31. if(hi <= lo) return;
  32. int j = partition(a,lo,hi);
  33. sort(a,lo,j-1);
  34. sort(a,j+1,hi);
  35. }
  36.  
  37. @SuppressWarnings("unchecked")
  38. private static boolean less(Comparable v, Comparable w){
  39. return v.compareTo(w) < 0;
  40. }
  41. private static void exch(Comparable[] a, int i, int j){
  42. Comparable t = a[i];
  43. a[i] = a[j];
  44. a[j] = t;
  45. }
  46. private static void show(Comparable[] a){
  47. for(int i=0; i<a.length; i++) StdOut.print(a[i] + " ");
  48. StdOut.println();
  49. }
  50. public static boolean isSorted(Comparable[] a){
  51. for(int i = 1; i < a.length; i++){
  52. if(less(a[i],a[i-1])) return false;
  53. }
  54. return true;
  55. }
  56. public static void main(String[] args){
  57. String[] a = new In().readAllStrings();
  58. sort(a);
  59. assert isSorted(a);
  60. show(a);
  61. }
  62. }

实际应用中经常会出现大量重复元素的排序情况,而快速排序在面对重复元素时排序复杂度并没有降低。Dijkstra提出的三向切分快速排序方法可以迅速降低这种情况下的复杂度,甚至有可能达到线性级别n,如荷兰国旗问题(见我的另一篇文章)。其基本思想就是选取切分点v,从左到右遍历,维护一个从前往后遍历的位置点lt,使得a[0]~a[lt-1]都小于v,维护一个从前往后遍历的位置点i,使得a[lt]~a[i-1]都等于v,维护一个从后往前的位置点,使得a[i]~a[gt]都大于v。

  1. /*
  2. * 三向切分的快速排序
  3. * a[lo...lt-1]中的元素都小于v
  4. * a[gt+1....hi]中的元素都大于v
  5. * a[lt...i-1]中的元素都等于v
  6. * a[i...gt]中的元素都还未确定,通过下面处理
  7. * 1. a[i]小于v,将a[lt]和a[i]交换,将lt和i加1
  8. * 2. a[i]大于v,将a[gt]和a[i]交换,将gt减1
  9. * 3. a[i]等于v,将i加1
  10. * 这些操作都会保证数组元素不变且缩小gt-i的值,这样循环才会结束
  11. */
  12. private static void sort3way(Comparable[] a, int lo, int hi){
  13. if(hi <= lo) return;
  14. int lt = lo;
  15. int i = lo+1;
  16. int gt = hi;
  17. Comparable v = a[lo];
  18. while(i <= gt){
  19. int cmp = a[i].compareTo(v);
  20. if(cmp<0) exch(a,lt++,i++);
  21. else if(cmp>0) exch(a,i,gt--);
  22. else i++;
  23. }//现在a[lo...lt-1] < v=a[lt...gt]<a[gt+1...hi]
  24. sort3way(a,lo,lt-1);
  25. sort3way(a,gt+1,hi);
  26. }

用这里的sort3way方法替代快速排序中的sort(Comparable[] a, int lo, int hi)即可。

快速排序及三向切分快排——java实现的更多相关文章

  1. 快速排序详解(lomuto划分快排,hoare划分快排,classic经典快排,dualpivot双轴快排源码)

    目录 快速排序(lomuto划分快排,hoare划分快排,classic经典快排,dualpivot双轴快排) 一.快速排序思想 二.划分思想 三.测试用例 快速排序(lomuto划分快排,hoare ...

  2. 快排+java实现

    import java.util.Arrays; public class QuickSort { //三数取中法.取出不大不小的那个位置 public static int getPivotPos( ...

  3. 数据结构65:快速排序算法(QSort,快排)

    上节介绍了如何使用起泡排序的思想对无序表中的记录按照一定的规则进行排序,本节再介绍一种排序算法——快速排序算法(Quick Sort). C语言中自带函数库中就有快速排序——qsort函数 ,包含在 ...

  4. 快排java实现

    package sort; public class QuickSort { public static final int cutoff = 3; /** * insertion sort * * ...

  5. 快排java代码

    定一个基准位,递归左右两边排序. public void fun(){ int arr[] = {2,3,4,5,6,7,822,3,4,5,8,6,5,4,2,1}; //System.out.pr ...

  6. 记录一个基于Java的利用快排切分来实现快排TopK问题的代码模板

    使用快排切分实现快排和TopK问题的解题模板 import java.util.Arrays; public class TestDemo { public static void main(Stri ...

  7. 快速排序 java实现 (原理-优化) 三路快排

    一.基本的快速排序 在数组中选取一个元素为基点,然后想办法把这个基点元素移动到它在排好序后的最终位置,使得新数组中在这个基点之前的元素都小于这个基点,而之后的元素都大于这个基点,然后再对前后两部分数组 ...

  8. Quick Sort(三向切分的快速排序)(Java)

    //三向切分的快速排序 //这种切分方法对于数组中有大量重复元素的情况有比较大的性能提升 public static void main(String[] args) { Scanner input ...

  9. Java基础进阶:APi使用,Math,Arrarys,Objects工具类,自动拆装箱,字符串与基本数据类型互转,递归算法源码,冒泡排序源码实现,快排实现源码,附重难点,代码实现源码,课堂笔记,课后扩展及答案

    要点摘要 Math: 类中么有构造方法,内部方法是静态的,可以直接类名.方式调用 常用: Math.abs(int a):返回参数绝对值 Math.ceil(double a):返回大于或等于参数的最 ...

随机推荐

  1. (转)Hibernate的一级缓存

    http://blog.csdn.net/yerenyuan_pku/article/details/70148567 Hibernate的一级缓存 Hibernate的一级缓存就是指Session缓 ...

  2. IOS内购--后台PHP认证

    参考网址:https://blog.csdn.net/que_csdn/article/details/80861408 http://www.php.cn/php-weizijiaocheng-39 ...

  3. 第一节:setTimeout和setInterval定时器

    区别:  setInterval函数的用法与setTimeout完全一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行. 取消定时器:(clearTim ...

  4. Miller Rabbin素数测试

    步骤 ①先写快速幂取模函数 ②MR算法开始 (1)传入两个参数一个是底数一个是n也就是幂数,如果n是一个合数那么可以判定,这个数一定不是素数 (2)然后开始寻找一个奇数的n去计算,如果最后满足a^d% ...

  5. Linux:在安装虚拟机时如何选择网络类型?

    如图所示工作站提供了5种网络模式,我们主要用的就是上面3种:桥接模式,NAT,仅主机 1,仅主机模式 仅主机模式:虚拟机用过vmnet1网卡与宿主机通信,但是不能与物理局域网内其他主机通信,可利用虚拟 ...

  6. centos中安装jdk

    1.上传jdk安装文件到根目录 2.解压到相关目录 (1)创建相应目录mkdir -p /usr/local/java (2)解压 tar -zxvf jdk-7u80-linux-x64.tar.g ...

  7. 使用 lua 编写 wireshark 协议解析插件

    一.平台 操作系统:windows 7 wireshark:1.10.3 lua:5.1 二.准备 lua 语言基本语法,特别是关于表操作和循环 wireshark 文档,包括用户使用文档和开发者文档 ...

  8. noip模拟赛 可耻

    题目描述 给定一个长度为偶数的排列 p,你每次可以选取 p 排列中相邻的两个元素,假如分别是 x 和 y,那 么把 x 和 y 加入一个序列 q 的末尾,并将 x 和 y 从排列 p 中删除.重复上述 ...

  9. App架构设计经验谈:接口”安全机制”的设计

    [原文地址 点击打开链接] 原创文章,转载请注明:转载自Keegan小钢 并标明原文链接:http://keeganlee.me/post/architecture/20160107 微信订阅号:ke ...

  10. PHP array_flip()

    定义和用法 array_flip() 函数返回一个反转后的数组,如果同一值出现了多次,则最后一个键名将作为它的值,所有其他的键名都将丢失. 如果原数组中的值的数据类型不是字符串或整数,函数将报错. 语 ...