随机取样算法

最近学习编程珠玑,看到随机取样算法,很不错,这里也整理下:


首先来看一个简单的取样算法,这里假定在不考虑重复的情况下,从1-N之间取出M个数来

void simpleRand(int m, int n)
{
    for (int i = 0; i < m; i++)
        cout << rand() % n + 1 << " ";
    cout << endl;
}
这样子的话,很容易得到如下的输出:


这样子的话,倒是适合“石头-剪刀-布”,一类的小游戏


但很多情况下,我们需要的是没有重复的随机数,如何从1-N中取出M个数呢,这里看看如下的伪代码

initialize set S to empty

Size = 0

  while Size < M do

    T := RandInt(1, N)

    if T is not in S then

      insert T in S

      Size := Size + 1

这个算法,很不错,由于集合存储不同数据,所以最终得到的随机样本中,没有重复数据,见代码

void simpleRand2(int m, int n)
{
	set<int> s;
	int size = 0;
	while (size < m)
	{
		int t = rand() % n + 1;
		if (s.find(t) == s.end())
		{
			s.insert(t);
			size++;
		}
	}
	
	for (set<int>::iterator i = s.begin(); i != s.end(); ++i)
		cout << *i << " ";
	
	cout << endl; 
}

这一次,得出的结果已经很不错了

可惜,还是有一个重大问题,如果M = N = 100呢,当Size = 99时,最后一个数,算法只能闭眼瞎猜,直到偶然碰到那个数,这平均需要猜测100个随机数。


好了,不要着急,我们额度改良算法马上就来到了

这里利用递归很容易理解,如果从1-10中选择5个数,那么只需要从1-9中产生一个4个数的样本,然后再加上第五个数即可了:

这里给出伪代码参考了:

function Sample(M, N)

  if M = 0 then

    return the empty set

  else

    S := Sample(M - 1, N - 1)

    T := RandInt(1, N)

    if T is not in S then

      insert T in S

    else

      insert N in S

  return S


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值