并行计算第k小的数

串行计算第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;
	}
	
}



 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值