(zz)随机数的生成

 

问题描述:

        现要求产生 0~n-1 范围内的 m 个随机整数的有序列表,且不允许重复,m <= n。

        考虑到 n 的值可能很大,而通常 C/C++ 提供的随机数产生器所能返回的随机数在 [0,RAND_MAX],其中,RAND_MAX 为 0x7FFF。也就是说只有 15 位的随机性。因此,我们需要要有自己的随机数产生器,以便能够返回更多位数的随机数,通常为 30 位。下面的函数可以满足我们的要求:

int bigrand()
{
return (RAND_MAX * rand() + rand());
}

注意,这里也可以采用将第一个 rand() 的返回值左移 15 位,然后加上第二个 rand() 的返回值的方法来提速。

        下面,我们就可以用这个随机数产生器来解决上面的问题了。看到这里,你是不是想到了什么解决方法呢。下面的方法来自算法大师 Donald Knuth。

void genknuth(int m, int n)
{
srand((unsigned int)time(NULL));

for(int i = 0; i < n; i++)
{
   if((rand() % (n - i)) < m)
   {
    cout<<i<<"\n";
    m--;
   }
}
}

其中的 srand 语句是我为了在每次运行时能够得到不同的随机数序列而加的。

         不知道这个方法有没有出乎你的意料,算上 for 循环才 4 句话。不过,就是这 4 句话,已经很完美地解决了上面提出的问题,有序、互异、m 个数。

        这个方法通过顺序扫描 0~n-1 范围内的每个数保证产生的随机数有序和互异。

        那产生 m 个数怎么保证呢?又没有类似循环的语句来控制产生的随机数的个数。

        要记住,程序语句只是我们实现某种功能的一种表现形式,这也就是说,我们要实现某种功能,可以由很多种表现形式。下面就来分析一下这个方法是如何保证能够产生 m 个随机数的。

         想必大家都已经看到产生的随机数都是在 if 语句中输出的,那也就是说 if 语句控制了产生的随机数的个数。因此,要说明能够产生 m 个随机数,只要说明 if 语句能够执行且仅能执行 m 次。

         首先,在 for 循环没有推出的情况下,if 语句最多能够执行 m 次,因为 if 语句的每次执行都会使 m 的值减 1,当 m=0 时,if 语句就不会再执行了。因为 (rand() % (n - i)) 是一个非负数。

         其次,我们分析 if 语句最少能够执行多少次。如果 if 语句开始一直得不到执行,那么 (n-i) 便会一直减小,直到与 m 相等。这时 (rand() % (n - i)) 一定小于 (n-i),也就是 m,从而使得 if 语句得到一次执行。而此时 for 循环已经执行了 (n-m+1) 次,离推出循环只剩下 (m-1) 次,要使得 if 语句能够执行 m 次,那么接下来的 (m-1) 次循环 if 语句必须都得能够执行。事实是什么样的呢?第一次 if 语句开始执行时,(n-i)=m,执行完时,(n-i) 和 m 都减少 1,从而仍然有 (n-i)=m 成立。这个过程一直持续到 m=0。刚好是 m-1 次。

         因此,我们可以相信 if 语句确实能够执行且只能执行 m 个。

        Donald Knuth 实在是太厉害了!

        顺便说一句,据说在大学期间,有关程序设计之类的比赛,只要有他参加,第一名非他莫属。


zz from: http://hi.baidu.com/xwf_like/blog/item/ff2a9b98293022006e068c2d.html

转载于:https://www.cnblogs.com/pangpangxiongxiong/archive/2009/08/21/1551245.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值