算法设计与分析——线性时间选择
private static Comparable (int p,int r,int k) { if(p==r) { return a[p]; } int i = randomizedaparttition(p,r); int j = i-p+1; //a[p:i]中元素的个数 if(k<=j) { return randomizeSelect(p,i,k); } else { return randomizeSelect(i+1,r,k-j); } }
找出的基准x至少比3(n-5)/10个元素大,因为在每一组中有2个元素小于本组的中位数,中位数处于1/2*[n/5-1]=(n-5)/10,即n/5个中位数中又有(n-5)/10个小于基准x。
同理,基准x也至少比3(n-5)/10个元素小。而当n≥75时,3(n-5)/10≥n/4所以按此基准划分所得的2个子数组的长度都至少缩短1/4。
这个其实比较容易理解:
数组中共n个元素,5个元素一组,一共分成约m=n/5组。每组中间大小的那个数不妨称其为“次中位数”。
在m=n/5个“次中位数”中再取出中间值,这就是整个数组的“中位数”X。
很显然,约有一半的“次中位数”比X还要小【(n-5)/10<m/2】
在这些组中,每组起码要有3个元素(连“次中位数”也算上)比X小,
所以整个数组中起码要有3(n-5)/10个元素比X小。
当n≥75时3(n-5)/10≥n/4,也就是说起码有1/4的元素比X小。
同理,起码也有1/4的元素比X还要大。
这样就保证了这个中位数的选择比较合理,划分之后最长的数组也不会超过原来的3/4,总体划分比较均匀。
假设你们年级有10个班,每个班只有5个人。
某次考试中,你在你们班考了第三名(次中位数)。
将每个班的第三名放在一起比较,你在这十个人中排第5名(中位数)。
那不就是在说,整个年级中至少有5*3+2=17个人成绩比你还要低?
private static Comparable select(int p,int r,int k) { if(r-p<5) { bubbleSort(p,r);//用某个简单排序算法对数组a[p:r]排序 return a[p+k-1]; } //将a[p+5*i]至a[p+5*i+4]的第3小元素与a[p+i]交换位置 //找中位数的中位数,r-p-4即上面所说的n-5 for(int i=0; i<=(r-p-4)/5; i++) { int s=p+5*i; int t=s+4; for(int j=0;j<3;j++) { bubble(s,t-j); } MyMath.swap(a,p+i,s+2); } Comparable x=select(p,p+(r-p-4)/5,(r-p+6)/10); int i=partition(p,r,x); int j=i-p+1; if(k<=j) { return select(p,i,k); } else { return select(i+1,r,k-j); } }