蓄水池采样法

看到一个非常有趣的题目,学会了一个非常巧妙的算法:

如何从n个数中随机的选择k个数?

如果采用直接产生随机数的方法,当n和m都很大时,随机数产生重复的概率会很大,算法性能会大大降低。

这里采用蓄水池算法,算法代码很简答,假设从n个数中选择k个数:

    for (int i=k+1;i<=n;i++)
    {
        int p=rand(1,i);
        if (p<=k)
            swap(i,p);
    }

解释一下算法是如何工作的:

先假设只有k个数,前k个数都已经被选择进入备选池,备选池内的数保证当前所有数据每个数被选择的概率相同。

这里使用数学归纳法来证明:

对第k+1个数:

被选择到进行交换的概率为k/(k+1),即发生替换的概率为k/(k+1)。

对于备选池内的每个数,被替换的概率为1/k,即备选池内每个数被替换的概率为k/(k+1)   *   1/k   =   1/(k+1),留下的概率为1-1/(k+1)=k/(k+1)。

假设第k+t个数成立,对k+t+1个数来说:

被选择到进行交换的概率为k/(k+t+1),即发生替换的概率为k/(k+t+1)。

对于备选池内的每个数,一个数在备选池内的概率为k/(k+t),被替换的概率为1/k,即备选池内每个数被替换的概率为k/(k+t+1)   *   1/k   =   1/(k+t+1),

留下的概率为(k/(k+t)) * (1-1/(k+t+1)) = k/(k+t+1)。

证明完毕。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值