取样问题——《编程珠玑》学习笔记

2 篇文章 0 订阅

一、问题描述

如何在一个样本库内随机选出若干个样本,不允许有重复?
如何打乱顺序?
关于具体问题描述,与详细分析过程请看《编程珠玑》第十二章,这里只记录我用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毫秒

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值