一、问题描述
如何在一个样本库内随机选出若干个样本,不允许有重复?
如何打乱顺序?
关于具体问题描述,与详细分析过程请看《编程珠玑》第十二章,这里只记录我用Java代码做的实现,以及主要思路
此例,可以用来生成一个随机样本文件,位图排序中可以使用
二、Java代码实现
package demo.rand;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import org.junit.Test;
import demo.time.Timer;
public class Sampling {
/**
*
* @param amount 取得数量
* @param start 取数起始值
* @param end 取数结束值
* @return
*/
public int[] genknuth(final int amount, int start , int end){
if(start > end ){
int t = start;
start =end;
end =t;
}
int select = amount;
int remaining = end - start;
int[] result = new int[amount];
Random rand = new Random();
for (int i = end ; i >= start ; i--) {
/*在剩余的n-i个整数中选择m个整数,选择下一个数的概率为 m/(n-i)
if( (bigrand() % (n-i)) < m) 一个非常大的随机数取余n-i小于m,选择这个数
其实等于获得一个随机的再[0,n-i)范围内的随机数
*/
int randInt = rand.nextInt( remaining);
//System.out.println("随机数为:"+randInt + " i= " + i +" remaining=" +remaining);
if( randInt < select ){
result[ --select] = i;
}
remaining --;
if(remaining == 0 ){
break;
}
}
return result;
}
/**
* 将一个数组写入文件
* @param path
* @param context
*/
public void writeToFile(final String path, final int[] context){
File file = new File(path);
if( !createFile(file)){
return;
};
StringBuilder sb = new StringBuilder();
for(int temp: context){
sb.append(temp + "\n");
}
try {
FileWriter fileWritter = new FileWriter(file,true);
BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
bufferWritter.write(sb.toString());
bufferWritter.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
//将有序数组打乱顺序
public int[] outOfOrder(final int[] context){
Random rand = new Random();
for(int i=0;i < context.length /2 + 1; i++){
int j = rand.nextInt(context.length - 1 -i) + i;
//与后面第随机数位置的数进行交换
int t= context[i];
context[i] = context[j];
context[j] = t;
}
return context;
}
public boolean getRandBool(){
Random rand = new Random();
if(rand.nextInt() % 2 == 0){
return false;
}else{
return true;
}
}
public boolean createFile(File file){
if( !file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
return true;
}
@Test
public void testGenknuth(){
Timer timer = new Timer();
timer.printRunTime();
int[] randInts = genknuth(1000000, 10000000, 99999999);
timer.printRunTime();
int[] noOrder = outOfOrder(randInts);
timer.printRunTime();
writeToFile("F:/ProgrammingPearls/randnum1.txt", noOrder);
timer.printRunTime();
}
}
三、算法
select = m
remaining = n
for i=[ 0 , n )
if ( bigrand() % remaining ) < select
print i
select –
remaining–
如果从remaining 个剩余整数中选出select 个,我们以概率s/r选择下一个数,这样选出来的就是一个有序的随机样本。
四、性能测试
在1000 0000到9999 9999范围内选取1000 0000个数字
取样运行时间为:1851.0毫秒
打乱顺序运行时间为:372.0毫秒
写入文件运行时间为:3154.0毫秒