Ex2_3_18三取样切分
import edu.princeton.cs.algs4.In;import edu.princeton.cs.algs4.StdOut;import edu.princeton.cs.algs4.StdRandom;public class Ex2_3_18 { private 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(lo <= hi + 5) { Insertion(a,lo,hi); return;}//以5为阈值进行插入排序 int j = partition(a,lo,hi); sort(a,lo,j-1); sort(a,j+1,hi); } private static int partition(Comparable[] a, int lo, int hi){ int i = lo; int j = hi + 1; while (true){ while (less(a[i++],a[midNum(a,lo,hi)])); while (less(a[lo],a[j--])); if(i >= j) break; exch(a,i,j); } exch(a,lo,j); return j; } //三取样,以中位数为切分元素,并把切分元素移动到末端作为标记 private static int midNum(Comparable[] a, int lo, int hi){ if( (a[lo].compareTo(a[lo+1]) * a[lo].compareTo(a[lo+2])) < 0){ exch(a,lo,a.length-1); return lo; } else if( (a[lo+1].compareTo(a[lo]) * a[lo+1].compareTo(a[lo+2])) < 0){ exch(a,lo+1,a.length-1); return lo+1; } else{ exch(a,lo+2,a.length-1); return lo+2; } } private static void Insertion(Comparable[] a, int lo, int hi){ for(int i = lo+1; i <= hi; i++){ for(int j = i; j>lo && less(a[j],a[j-1]); j--){ exch(a,j,j-1); } } } private static boolean less(Comparable v, Comparable w){ return v.compareTo(w) < 0; }//比较v是否小于w 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 void main(String[] args){ String[] a = In.readStrings(); sort(a); show(a); }}
要点:
- 取样以子数组前三个数的中位值为切分元素: Comparable v = a[midNum(a,lo,hi)];
- midNum方法在返回中位元素索引同时,交换其与末尾元素,这样在partition内循环中,右子数组循环 while (less(a[i++],a[midNum(a,lo,hi)]));就无需边界检查,因为最终一定a[hi]==v退出循环;while (less(a[lo],a[j—]));j减为lo时一定a[lo]==v退出循环