概率取样问题

  问题:程序输入两个整数m和n,其中m<n。输出是0~n-1范围内的m个随机整数的有序列表,不允许重复,要求每个选择出现的概率相等。
  (1)扫描算法:扫描0~n-1,通过一个概率测试来对每个整数进行选择,可保证输出结果是有序的。考虑m=2,m=5的情况。选择的0的概率为2/5,通过语句if(bigrand()%5)<2来实现。若选择了0,则在剩下的4个数中以1/4的概率选择一个数。若未选择0,则以2/4的概率选择下一个数,这样就能保证恰好能选出m个整数。这里bigrand()返回一个很大的随机整数,远大于m和n。一般来说,如果要从r个剩余整数中选择s个,我们以概率s/r选择下一个整数。

  显然,算法的运行时间为O(n)。
  (2)基于集合的算法:在一个初始为空的集合里面插入随机整数,直到个数足够,核心问题是如何实现集合S。我们可以考虑有序链表、二叉树等数据结构,但最直接的办法是利用C++标准模板库中的set容器。

  C++ STL规范要求每次插入操作都在O(logm)时间内完成,而遍历集合则需要O(m)时间。因此整个程序需要O(mlogm)时间(当m相对于n较小时)。但是该数据结构的空间开销比较大。
  当n比较大而m接近于n时,基于集合的算法需要生成大量的随机数,而其中很多随机数都要丢掉(因为之前集合中已经存在这个数了),这导致很多不必要的运行时间开销。Bob Floyd给出了一个算法,使得即使在最坏情况下也只使用m个随机数。如下(C++实现):

  (3)排序算法:生成随机整数的有序子集的另一种方法是把包含整数0~n-1的数组顺序打乱,然后把前m个元素排序输出。

  算法需要n个元素的内存空间和O(n+mlogm)的时间。
  关键算法设计思想:扫描策略、概率测试(随机数生成)、集合数据结构、搜索策略、排序策略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值