三类随机问题
1. 已有n条记录,从中选取m条记录,选取出来的记录前后顺序不管。
实现思路:按行遍历所有记录,约隔n/m条取一个数据即可
2. 在1类情况下,还要求选取出来的m条记录是随机排序的
实现思路: 给n条记录,分别增加一列标记,值为随机选取的1至n之间的不重复数据,
实现参考博文 将文件内容按行随机排列
3. 区别于1,2类问题, 如果记录是有权重的,如何结合权重去随机选取。 比如A的权重为10, B的权重股为5, C的权重为1, 则随机选取4个时可能应该出现AABB。
4. 第四类比较特殊,是对于记录条数未知的带有权重的随机抽样问题,具体算法可以参照附件中的论文:Random Sampling with a Reservoir
这第三类问题是本文重点,下面开始解决。
实现思路: 以 A:10, B:5, C:1 三条记录上随机选取4条为例,(是否以权重排序这个无所谓)
对于
A 10
B 5
C 1
首先,将第n行的数值赋为第n行加第n-1行的,递归执行,如下:
A 10
B 15
C 16
(这一步主要是保证整个序列是递增有序的,并且相邻元素之间的间隔长度代表元素被选取的概率,然后根据随机算法落到每个区间的值就代表了每个元素被抽取到的概率)
然后每次从[1,16]随机选取一个数,如果落在[1,10]之间,则选取A,如果落在(10,15]之间则选B,如果落在(16,16]之间则选取C, 图示如下,谁占的区间大(权重高),被选上的概率更大。
知道了思路,实现起来就比较方便了, 需要考虑的一点可能就是我随即选了一个数值,比如12,我怎么跟B对应上? 其实也比较简单,用二分法查找即可。
下面附上实现代码:
- #include <string>
- #include <cstdlib>
- #include <vector>
- using namespace std;
- const int LEN = 4098;
- const int MAX_QUERY_LEN = 2048;
- //返回属于[p,q)的随机数