水塘抽样解析
什么是水塘抽样(参考百度百科)
水塘抽样是一系列的随机算法,其目的在于从包含n个项目的集合S中选取k个样本,其中n为一很大或未知的数量,尤其适用于不能把所有n个项目都存放到内存的情况。最常见例子为[Jeffrey Vitter](https://baike.baidu.com/item/Jeffrey Vitter)在其论文中所提及的算法R。
算法步骤(参考百度百科)
参照Dictionaryof Algorithms and Data Structures所载的O(n)算法,包含以下步骤(假设阵列S以0开始标示): [1]
从S中抽取首k项放入「水塘」中
对于每一个S[j]项(j ≥ k):
随机产生一个范围从0到j的整数r
若 r < k 则把水塘中的第r项换成S[j]项
实现
//假设集合的总长度是n 需要从n中随机取k个
public String[] random(int k,String[] ns){
String[] rs = new String[k];
Random random = new Random();
for(int i=0,len=ns.length;i++){
//首先 先将前k最为结果保存
if(i<k){
rs[i] = ns[i];
}else{
//第k+1次,取随机数,随机数<k,就将随机数所对应的值替换成当前值
int tmp = random.nextInt(i);
if(tmp < k){
rs[tmp] = ns[i];
}
}
}
return rs;
}
验证
我们可以看到,第n行被抽中的概率Pn为k/n,那么还需要算上后续的n+1-N次不被覆盖的概率即下面的算法。其中Pj表示第**j(n+1…N)**次抽中的概率为k/j,那么覆盖第n次即j-1的概率为Pj/k,最终得到k/N,第n行的概率至于k和N相关,即等概率。