第三周下:QuickSort

Java sort for primitive types

1. Quicksort

  1. 思路:

    • 打乱array中的item顺序(用来保障Performance)
    • 锚定一个item,比如第一个a[lo],比它大的都去右边,比它小的都去左边
      • i pointer:从左到右扫,直到a[i] > a[lo]时停下
      • J pointer:从右到左扫,直到a[j] < a[lo]时停下
      • 交换a[i]和a[j]
      • 全部结束后(i>=j),交换a[lo]和a[j]
    • 递归地将所有排好
  2. Performance

    • best case:~N \lg N compares
    • worst case: ~ \frac{1}{2} N^2 compares
    • Average: ~2N \ln N compares,~\frac{1}{3} N \ln N
      • Compares 比 merge sort 多39%
      • 但因为更少的data movement,所以比merge sort要快
  3. Stability

    • Quicksort is not stable
  4. Java implementation

    import edu.princeton.cs.algs4.StdRandom;
    
    public class Quick{
     private static int partition(Comparable[] a, int lo, int hi){
         int i = lo;
         int j = hi + 1;
         while(true){
             // 找到比a[lo]大的a[i]
             while(less(a[++i], a[lo])){
                 if(i == hi){
                     break;
                 }
             }
             // 找到比a[lo]小的a[j]
             while(less(a[lo], a[--j])){
                 if(j == lo){
                     break;
                 }_
             }
             // 检查i,j是否已经跨过彼此(即i>=j),是的话就结束
             if(i >=j){
                 break;
             }
             // 交换a[i],a[j]
             exch(a, i, j);  
         }
         // 狡猾a[lo],a[j]
         exch(a, lo, j);
         // 返回j,代表已经排好的item所在的index
         return j;
    
     }
    
     public static void sort(Comparable[] a){
         // shuffle让performance至少大概率不会在worst case
         StdRandom.shuffle(a);
         sort(a, 0, a.length-1);
     }
    
     private static void sort(Comparable[] a, int lo, int hi){
         // 递归地终止条件
         if(hi <= lo){
             return;
         }
    
         // 优化1:对于比较小的array(定cutoff=10),用quick sort太浪费memory,改用insertion sort
         int cutoff = 7;
         if(hi <= lo+cutoff - 1){
             Insertion.sort(a); // Insertion.java与Merge.java放在同一个目录下
             return;
         }
             // 结束优化1
    
         // 优化2:不再随意地直接选第一个item,即a[lo]来锚定,而选用a[lo], a[hi], a[(lo+hi)/2]中的median
         int m = medianOf3(a, lo, (lo+hi)/2, hi);
         exch(a, lo, m);  
         // 结束优化2
    
         int j = partition(a, lo, hi);
         sort(a, lo, j-1);
         sort(a, j+1, hi);
     }
    
     // item v,w比较大小
     private static boolean less(Comparable v, Comparable w){
         return v.compareTo(w) < 0
     }
    
     // a[i]和a[j]交换位置
     private static void exch(Comparable[] a, int i, int j){
         Comparable swap = a[i];
         a[i] = a[j];
         a[j] = swap;
     }
    
     private static int medianOf3(Comparable[] a, int lo, int md, int hi){
         int[] arr3 = new int[];
         arr3[0] = a[lo];
         arr3[1] = a[md];
         arr3[2] = a[hi];
         Insertion.sort(arr3);
         return 
     }
    }
    

2. Selection

  1. 目标:给定一个array(有n个items),找到第k个最小的item
  2. 思路:
    • 找到合适的a[j],它的左边都比它小,右边都比它大
    • 根据j,在一个subarray中重复,直到找到j=k
    • (代码见上方)
  3. Performance
    1. on average:take linear time,~ 2N compares
    2. worst case:~\frac{1}{2}N^2 compares (但已经靠random shuffle来提供一个probabilistic guarantee了)

3. Duplicate keys

  1. Quicksort问题:

    • 遇到和锚定的item相同时,会将相同的item都放在锚定的item的一边,这样是很没效率的。因为,当所有key全部相同时,需要比较$\frac{1}{2}N^2$次。我们希望,它在遇到相同的item时就能停下来,不改变这个item的位置。这样当所有key都相同时,只需比较 N \lg N
  2. 思路(3-way partitioning):

    • 锚定item v,比如选第一个item a[lo]。

    • v相同的都放在lt和gt之间,lt左边的item都小于v,gt*右边的item都大于v

      • 当a[i] < v时,a[lt]和a[i]交换,lt和i都+1
      • 当a[i] > v时,a[gt]和a[i]交换,gt-1
      • 当a[i] == v时,i+1
  3. Java implementation

    import edu.princeton.cs.algs4.StdRandom;
    
    public class Quick3Way{
     public static void sort(Comparable[] a){
         // shuffle让performance至少大概率不会在worst case
         StdRandom.shuffle(a);
         sort(a, 0, a.length-1);
     }
    
     private static void sort(Comparable[] a, int lo, int hi){
         int lt = lo;
         int gt = hi;
         int i = lo;
         Comparable v = a[lo];
    
         if(hi <= lo){
             return;
         }
    
         while(i <= gt){
             int cmp = a[i].compareTo(v);
             if(cmp < 0){ // a[i] < v
                 exch(a, lt++, i++);
             }else if(cmp > 0){ // a[i] > v
                 exch(a, i, gt--);
             }else{
                 i++;
             }
         }
    
         sort(a, lo, lt-1);
         sort(a, lt+1, hi);
     }
    
     // a[i]和a[j]交换位置
     private static void exch(Comparable[] a, int i, int j){
         Comparable swap = a[i];
         a[i] = a[j];
         a[j] = swap;
     }
    }
    

4. System sorts

  1. Java system sorts: Array.sort()

    • 遇到Reference types: 用merge sort。优点:稳定,保证N \lg N 的compares
    • 遇到primitive types:用quick sort。优点:占用更少的memory,更快
    import java.util.Arrays
    import edu.princeton.cs.algs4.StdIn;
    import edu.princeton.cs.algs4.StdOut;
    
    public class StringSort{
      public static void main(String args){
        String[] a = StdIn.readString();
        Array.sort(a);
        for(int i = 0; i < a.length; i++){
          StdOut.println(a[i]);
        }
      }
    }
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容