蓄水池抽样问题

1.问题描述:

随机抽样问题表示如下:
要求从N个元素中随机的抽取k个元素,其中N无法确定。
这种应用的场景一般是数据流的情况下,由于数据只能被读取一次,而且数据量很大,并不能全部保存,因此数据量N是无法在抽样开始时确定的;但又要保持随机性,于是有了这个问题。所以搜索网站有时候会问这样的问题。

2. k =1的情况:

解法:我们总是选择第一个对象,以1/2的概率选择第二个,以1/3的概率选择第三个,以此类推,以1/m的概率选择第m个对象。当该过程结束时,每一个对象具有相同的选中概率,即1/n,证明如下。

        证明:第m个对象最终被选中的概率P=选择m的概率*其后面所有对象不被选择的概率,即:

                                                           

3. k != 1 && n > k的情况:

 对应蓄水池抽样问题,可以类似的思路解决。先把读到的前k个对象放入“水库”,对于第k+1个对象开始,以k/(k+1)的概率选择该对象,以k/(k+2)的概率选择第k+2个对象,以此类推,以k/m的概率选择第m个对象(m>k)。如果m被选中,则随机替换水库中的一个对象。最终每个对象被选中的概率均为k/n,证明如下。

        证明:第m个对象被选中的概率=选择m的概率*(其后元素不被选择的概率+其后元素被选择的概率*不替换第m个对象的概率),即
                                                        

4. 代码:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
 
using namespace std;
 
typedef vector<int> IntVec;
typedef typename IntVec::iterator Iter;
typedef typename IntVec::const_iterator Const_Iter;
 
// generate a random number between i and k,
// both i and k are inclusive.
int randint(int i, int k)
{
	if (i > k)
	{
		int t = i; i = k; k = t; // swap
	}
	int ret = i + rand() % (k - i + 1);
	return ret;
}
 
// take 1 sample to result from input of unknown n items.
bool reservoir_sampling(const IntVec &input, int &result)
{
	srand(time(NULL));
	if (input.size() <= 0)
		return false;
 
	Const_Iter iter = input.begin();
	result = *iter++;
	for (int i = 1; iter != input.end(); ++iter, ++i)
	{
		int j = randint(0, i);
		if (j < 1)
			result = *iter;	
	}
	return true;
}
 
int main()
{
	const int n = 10;
	IntVec input(n);
	int result = 0;
 
	for (int i = 0; i != n; ++i)
		input[i] = i;
	if (reservoir_sampling(input, result))
		cout << result << endl;
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值