随机算法

1. 要求从N个元素中随机的抽取1个元素。


2. 要求从N个元素中随机的抽取K个元素。

复制代码
int  remain  =  N
int  select  =  K
for  ( int  i  =   0 ; i  <  N;  ++ i){
   
if  (rand() %  remain  <  select){
      cout
<< i << "   " ;
      
--select;
   }
   
-- remain;
}
复制代码

 

第一个元素被选中的概率为 K/N

第二个元素被选中的概率为(K/N)*((K-1)/(N-1)) + ((N-K)/N) * (K/(N-1)) = K/N

.........

证明略(参看The Art of Computer Programming III)


3. 要求从N个元素中随机的抽取1个元素, 其中N无法确定(数据流)。

复制代码
int  Num;
int  i  =   0 ;
int  choose  =   0 ;
while (scanf( " %d " & Num) &&  Num  !=   0 ){
   
if  ((( double )rand() / ( double )RANDOM_MAX)  <  ( 1.0   /  ( double ) ++ i))
      choose 
=  Num;
}
cout 
<<  choose  << endl;
复制代码


总是选择第一行, 二分之一几率选择第二行, 以此类推, K分之一机率选择第K行, 当while 执行完毕,假设N个数字,则每个数字被选择的机率均为1/N

第一行被选择的机率为:

1 * 1/2 * 2/3 * 3/4 *.... (N-1)/N = 1/N

第K行被选择的机率为:

1/K * K/(K+1) * .... (N-1)/N = 1/N


4. 要求从N个元素中随机的抽取K个元素, 其中N无法确定(数据流)。

reservoir sampling

// Init : a reservoir with the size: K
for ( int  i  =  K; i  <  N;  ++ i){
   
int  M  =  rand()  %  i;
   
if ( M  <  K)
      SWAP the Mth value and ith value
}


解决方案就是蓄水库抽样(reservoid sampling)。主要思想就是保持一个集合(这个集合中的每个数字出现),作为蓄水池,依次遍历所有数据的时候以一定概率替换这个蓄水池中的数字。

(1)初始情况。出现在水库中的k个元素的出现概率都是一致的,都是1。这个很显然。

(2)第一步。第一步就是指,处理第k+1个元素的情况。分两种情况:元素全部都没有被替换;其中某个元素被第k+1个元素替换掉。

我们先看情况2:第k+1个元素被选中的概率是k/(k+1)(根据公式k/i),所以这个新元素在水库中出现的概率就一定是k/(k+1)(不管它替换掉哪个元素,反正肯定它是以这个概率出现在水库中)。下面来看水库中剩余的元素出现的概率,也就是1-P(这个元素被替换掉的概率)。水库中任意一个元素被替换掉的概率是:(k/k+1)*(1/k)=1/(k+1),意即首先要第k+1个元素被选中,然后自己在集合的k个元素中被选中。那它出现的概率就是1-1/(k+1)=k/(k+1)。可以看出来,旧元素和新元素出现的概率是相等的。

情况1:当元素全部都没有替换掉的时候,每个元素的出现概率肯定是一样的,这很显然。但具体是多少呢?就是1-P(第k+1个元素被选中)=1-k/(k+1)=1/(k+1)。

(3)归纳法:重复上面的过程,只要证明第i步到第i+1步,所有元素出现的概率是相等的即可。参见:http://wansishuang.javaeye.com/blog/443902


5. Shuffle (Fisher–Yates shuffle)

复制代码
void  shuffle( int  cards[],  int  n){
    
while  (n  >   1 ){
        
//  Swap a random unshuffled card with the top-most card
         int  k  =  rand()  %  n -- ;
        swap(cards[n], cards[k]);
    }
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值