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

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

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

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

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

 package 排序;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
/**
* @author evasean www.cnblogs.com/evasean/
*/
@SuppressWarnings("rawtypes")
public class Quick快速排序 {
private static int partition(Comparable[] a, int lo, int hi){
int i = lo;
int j = hi+1;
Comparable v = a[lo];//切分元素
while(true){
while(less(a[++i],v))
if(i==hi) break;
while(less(v,a[--j]))
if(j==lo) break;
if(i>=j) break;
exch(a,i,j);
}
exch(a,lo,j);//此时j<=i,且v > a[j],将切分元素v放入正确位置
return j;
}
public static void sort(Comparable[] a){
StdRandom.shuffle(a); //消除最坏的情况
sort(a,0,a.length-1);
}
private static void sort(Comparable[] a, int lo, int hi){
if(hi <= lo) return;
int j = partition(a,lo,hi);
sort(a,lo,j-1);
sort(a,j+1,hi);
} @SuppressWarnings("unchecked")
private static boolean less(Comparable v, Comparable w){
return v.compareTo(w) < 0;
}
private static void exch(Comparable[] a, int i, int j){
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
private static void show(Comparable[] a){
for(int i=0; i<a.length; i++) StdOut.print(a[i] + " ");
StdOut.println();
}
public static boolean isSorted(Comparable[] a){
for(int i = 1; i < a.length; i++){
if(less(a[i],a[i-1])) return false;
}
return true;
}
public static void main(String[] args){
String[] a = new In().readAllStrings();
sort(a);
assert isSorted(a);
show(a);
}
}

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

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

用这里的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. 集合Set、List、Map的遍历方法

    package com.shellway.javase; import java.util.ArrayList; import java.util.Collection; import java.ut ...

  2. (转)Hadoop入门进阶课程

    http://blog.csdn.net/yirenboy/article/details/46800855 1.Hadoop介绍 1.1Hadoop简介 Apache Hadoop软件库是一个框架, ...

  3. windows 设置注册表服务自动启动

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\xxx\Start = ,=自动,,=禁用

  4. C# 获取表中最大值

    ; if (db.LPicture.Any()) { // LPicture Newmode = db.LPicture.Where(n => ).FirstOrDefault(); start ...

  5. c++ map: 当map的value是void*指针

    #include <iostream> #include <map> #include <vector> using namespace std; //key is ...

  6. copy and rename a file multiple times using Matlab

    for file.txt***********n=10;fileinfo=importdata('file.txt');for i=1:nfilename=sprintf('file_%d.txt', ...

  7. Beetl学习总结(1)——新一代java模板引擎典范 Beetl入门

    1. 什么是Beetl Beetl目前版本是2.7.0,相对于其他java模板引擎,具有功能齐全,语法直观,性能超高,以及编写的模板容易维护等特点.使得开发和维护模板有很好的体验.是新一代的模板引擎. ...

  8. JavaSE 学习笔记之String字符串(十四)

    API:(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力,而又无需访问源 ...

  9. Debug 集子

    一. 001.c: 在函数 'main' 中: 001.c:8: 错误:'start' 的存储大小未知 001.c:9: 错误:'end' 的存储大小未知 ====================== ...

  10. [bzoj1007][HNOI2008]水平可见直线_单调栈

    水平可见直线 bzoj-1007 HNOI-2008 题目大意:给你n条直线,为你从上往下看能看见多少跳直线. 注释:能看见一条直线,当且仅当这条直线上存在一条长度>0的线段使得这条线段上方没有 ...