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退出循环