zoukankan      html  css  js  c++  java
  • 快速排序及三向切分快排——java实现

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

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

    快速排序的运行时间在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)即可。

  • 相关阅读:
    排序算法系列之冒泡排序 (3)
    排序算法系列之选择排序 (2)
    排序算法系列之插入排序 (1)
    深挖 NGUI 基础 之UICamera (二)
    深挖 NGUI 基础 之UIRoot (一)
    JPS寻路和AStar寻路
    旋转矩阵
    [斜边的血条进度]
    UI框架:ui节点控件的绑定方式
    Shader播放序列帧
  • 原文地址:https://www.cnblogs.com/evasean/p/7233817.html
Copyright © 2011-2022 走看看