您的位置:首页 > 编程语言

编程珠玑 12 取样问题

2013-06-29 22:08 246 查看
问题:从0到n-1的n个数中,随机选取m个数字,并且顺序打印出来,可以使用标准库的rand()函数

方法:使用Knuth方法,使用rand() % n < m表示概率m/n,在抽样中,加入m = 2, n = 5,那么第一次抽取0,我们有2/5的概率选择0,如果选择了0,那么在剩余的4个数中选取1的概率应该改为1/4,如果没有选取0,那么以2/4的概率选取1,这样5个数中选取1的概率还是2/5 * 1/4 + 3/5 * 2/4 = 2/5,这样选取1的概率还是2/5。

代码:

[cpp] view
plaincopy

#include <iostream>

#include <cstdlib>

#include <cstdio>

#include <ctime>

using namespace std;

void genknuth(int m, int n)

{

clock_t start, end;

start = clock();

srand(time(NULL));

for(int i = 0; i < n; i++)

{

if(rand() % (n - i) < m)

{

cout<< i << endl;

if(!(--m))

break;

}

}

end = clock();

std::cout << "Process took " << (double(end - start) / CLOCKS_PER_SEC) << "seconds" << endl;

return ;

}

int main()

{

genknuth(20, 1<<30);

return 0;

}

在n较小时,我们的效率比较高,但是当n非常大,接近2^32时,花费时间越来越多,但是代码非常简洁,高效!

-----------------------------------------------

编程珠玑12章后的第10题:

如何在事先不知道文本文件行数的情况下读取该文件,从中随机选择并输出一行?

解法:首先以概率1选择第一行,如果有更多行,比如第i行,我们以1/i的概率选择第i行,最后输出我们选择的行

伪代码:

-----------------------------------------------

-----------------------------------------------

p = 0

i = 0

while more input lines

with the conditional p = 1.0/++i select this line

choice = the i-th line

end while

print choice

-----------------------------------------------

-----------------------------------------------

最后输出结果,其中p = 1.0 / i++ 可以通过rand() % ++i < 1得到,如果满足条件,我们选择第i行。

【转】

扩展:原问题可简化为:如何从n个有序对象中等概率地任意抽取1个,简记为sample(n,1),其中n未知;

若将该问题改为:如何从n个有序对象中等概率地任意抽取m个,简记为sample(n,m),其中n未知;

分析:若n已知,sample(n,m)是普通的抽样问题;当n未知时,可否根据上述算法进行相应的转化求解?

解决方案:将sample(n,m)问题转化为m个sample(n*,1)问题,更具体一点是,转化为sample(n,1);sample(n-1,1);sample(n-2,1)....;sample(n-m+1,1)问题。仍然以一篇6行文档为例,任取其中2行,做法如下:第一遍,以如下概率选中一行:1(1) 2(1/2) 3(1/3) 4(1/4) 5(1/5) 6(1/6)假设选中第2行,接着概率修改如下:3(1) 4(1/2) 5(1/3)
6(1/4) 1(1/5)
【说明】:当选中第2行,从第3行开始修改概率,并将第2行排除在外,继续扫描,这样能保证在剩下的5个数中仍然以等概率抽取其中的一个。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: