从蓄水池算法到大数据算法一般性的一点看法

【需求】给定一个数据流,数据流长度N非常大,且N直到处理完所有数据之前都不可知,如何在只遍历一遍数据( 复杂度O(N) )的情况下,随机选取出m个不重复的数据。

这个需求通常会出现在大数据应用案例当中,通常是从大规模的数据集当中选择出一组目标数据。难点在于:
1、由于数据的规模庞大,无法一次性加载到内存中进行处理
2、只遍历一遍
3、要保证随机选取
4、每个数据被选到的的概率均等

这个需求其实和对庞大数据量中求取TOP(N)亦或者对庞大数据文件中的数据进行排序需求都有些相似的地方

我们可以发现,对于这类问题,有共性的解法,只不过在具体实现细节上有差别

共性在于:
1、寻找一个中间桥梁(数据结构容器,数组、队列、堆等等)来容纳求目标需求所必要的数据元素
2、确定数据进、出逻辑(Input、Output)
3、确定桥梁中数据替换办法(确定算法)

拿蓄水池算法来说
1、中间桥梁便可以是一个固定长度数组
2、数据源源不断地读入(一次遍历)、最终遍历完成后将数组数据写出
3、确定数组中容纳的m个数据的替换办法,也就是说对每一个元素,决定其是留在数组还是丢弃,只需保证每个元素被留下的概率均为m/N即可

那么重点在于确定第三点的替换算法

先看其中一个解决办法:我们只通过3个元素来以小见大,数组arr固定长度为2,也就是三选二,问题也就转化为我们让这依次过来的三个元素留在数组中的概率均为三分之二。

假设依次过来的三个元素为A、B、C

开始:
A、B入队,arr[0]=A,arr[1]=B
然后:
过来C,也只剩下C元素,那如何保证A留在数组中的概率为2/3

我们反过来想,是不是只需确保A被C取代的概率为1/3即可

那此时我们已知哪些条件?
1、总共过来了3个元素,3可用
2、数组长度为2,于是2可用
3、数组之外的元素个数为3-2=1,于是1可用

我们的目标就是要得到1/3这个值,那从排列组合角度来讲,我们很容想到,从三个数中任选一个数,那每个数被选中的概率刚好是1/3

也就是说,对于超过数组长度m的数,每来一个(第i个,i=m+1,m+2,m+3…),我们从[1,i]中取一个随机数,如果随机数大小落在数组长度内,我们就替换掉数组长度内的那个对应值,如果落在数组长度外,我们就不替换。

我们来验证这个结论:
还是先以上边的3个示例来验证
因为数组长度为2,对于过来的A、B两个元素,来了直接进数组,如果没有第三个元素,那么
A在数组中的概率为2/2=1
B在数组中的概率为2/2=1
如果有第三个元素(对应C),那么
A存在于数组中的概率为
[1,3]取随机值(取到1A就得被C替换),取到1的概率为1/3,那么取不到1的概率为2/3,则A最终被选中的概率为1*2/3=2/3
B同A
对于C,C想留在数组中,那么从[1,3]中取随机值,取到1或者2,C都可以留在数组中,其概率也为2/3

即符合我们的结论

推广其普适性:对于数组大小为m,流总长度为N,我们对第i个元素进行处理

还是一样,对于i<=m,过来的元素直接进入数组
从第i(=m+1)个元素开始,对[1,i]取随机数,落在[1,m]上则替换,落在[1,m]外则不替换

那么第i个元素,最终在数组中的概率为:第i个元素来的时候进入到数组中的概率*在后续第i+1到N个元素过来时均不被取代的概率

[1,i]中取的随机值落在[1, m]上(记为k): m/i
[1,i+1]中取的随机值落在k以外: (i+1-1)/(i+1) =i/(i+1)
[1,i+2]中取的随机值落在k以外: (i+2-1)/(i+2) =i+1/(i+2)

则第i个元素,最终在数组中的概率为:
m/i * i/(i+1) * (i+1)/(i+2)*…*(N-2)/(N-1)*(N-1)/N=m/N

即与推论吻合。

发布了95 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43878293/article/details/103436189