串行计算第k小的数的算法有很多,比如用堆,用一个长度为k的队列。这里说一下如何并行计算这个问题。原理很简单,将数列分为两半,在两半部分分别查找前k个数,然后合并,得到整个数列的前k个数。由此即可得到第k小的数。
用java实现的代码如下所示。
package org;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Hello, world!");
// int[] arr3 = {1000, 0, 6, 5, 4, 3, 2, 1, 7, 156, 44, 23, 123, 11, 50, 454, 234, 99, 32, 45};
Integer[]arr3=new Integer[1000];
Random ran=new Random();
for(int k=0; k<arr3.length; ++k)
arr3[k]=ran.nextInt();
QuickSelect<Integer>quick=new QuickSelect<Integer>(arr3);
for (int k = 1; k < 50; ++k) {
int sel = quick.select(k);
// System.out.printf("%d-th number is %d\n", k, sel);
Arrays.sort(arr3);
int sel2=arr3[k-1];
if(sel!=sel2)
System.out.printf("Error: %d-th, sel=%d, sel2=%d\n", k, sel, sel2);
for(int j=0; j<arr3.length; ++j)
arr3[j]=ran.nextInt();
// System.out.printf("%d-th number is %d\n", k, arr3[k - 1]);
}
}
}
class QuickSelect<T extends Comparable<T>> implements Runnable{
private T[] arr;
private int kTh;
private int start;
private int end;
private int limitLen;
private T[]result;
public QuickSelect(T[] arr){
this.arr=arr;
start=0;
end=arr.length;
}
public T select(int kTh){
this.kTh=kTh;
limitLen=(int) Math.round(Math.sqrt(kTh*arr.length));
Thread thread=new Thread(this);
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return result[kTh-1];
}
private QuickSelect(T[]arr, int start, int end, int kTh, int limitLen){
this.arr=arr;
this.start=start;
this.end=end;
this.kTh=kTh;
this.limitLen=limitLen;
}
public void run() {
System.out.printf("k=%d, start=%d, end=%d\n", kTh, start, end);
int len=end-start;
if(len<=kTh){
result=Arrays.copyOfRange(arr, start, end);
Arrays.sort(result);
}else if(len<=limitLen){
result=Arrays.copyOfRange(arr, start, start+kTh);
Arrays.sort(result);
//insert
for(int j=start+kTh; j<end; ++j){
int i=result.length-1;
if(arr[j].compareTo(result[i])<0){
result[i]=arr[j];
while(i>0&&result[i].compareTo(result[i-1])<0){
T tmp=result[i];
result[i]=result[i-1];
result[i-1]=tmp;
--i;
}
}
}
}else{
QuickSelect<T> runleft=new QuickSelect<T>(arr, start, start+len/2, kTh, limitLen);
QuickSelect<T> runright=new QuickSelect<T>(arr, start+len/2, end, kTh, limitLen);
Thread leftThread=new Thread(runleft);
Thread rightThread=new Thread(runright);
leftThread.start();
rightThread.start();
try {
leftThread.join();
rightThread.join();
result=merge(runleft.result, runright.result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private T[]merge(T[]left, T[]right){
int len;
if(left.length+right.length<=kTh){
len=left.length+right.length;
}else
len=kTh;
@SuppressWarnings("unchecked")
T[]r=(T[])Array.newInstance(arr[0].getClass(), len);
int p=0, q=0;
for(int j=0; j<len; ++j){
if(left[p].compareTo(right[q])<0){
r[j]=left[p];
++p;
}else{
r[j]=right[q];
++q;
}
}
return r;
}
}