文章目录
- 一、线性同余法生成随机数
- 二、洗牌算法
- 三、蓄水池抽样
- 1、如何随机从n个对象中选择一个对象?
- 2、如何随机从n个对象中选择k个对象?
一、线性同余法生成随机数
线性同余法是一种使用很广泛的伪随机数生成器算法:
R(n+1)=(A * R(n) + C) mod M; // 一般选取互质的A、C、M,而且M一般比较大
简而言之,线性同余法就是将当前的伪随机数值乘以A再加上C,然后将除以M得到的余数作为下一个伪随机数。
二、洗牌算法
FisherYates洗牌算法:
1. 初始化原始数组和新数组,原始数组长度为n(已知);
2. 从还没处理的数组(假如还剩k个)中,随机产生一个[0, k)之间的数字p(假设数组从0开始);
3. 把第p个数取出与第k个数交换;
4. 重复步骤2和3直到数字全部取完;
5. 从步骤3取出的数字序列便是一个打乱了的数列。
下面证明其随机性,即每个元素被放置在新数组中的第i个位置是1/n(假设数组大小是n)。一个元素m被放入第i个位置的概率P = 前i-1个位置选择元素时没有选中m的概率 * 第i个位置选中m的概率,即:
void Fisher_Yates_Shuffle(deque<int> &arr,vector<int> &res)
{
srand((unsigned)time(NULL));
for(int k = len - 1; k > 0; k--)
{
int p = rand()%(i + 1);
swap(arr[k], arr[p]);
}
}
三、蓄水池抽样
蓄水池抽样(Reservoir Sampling )是一个很有趣的问题,它能够在o(n)时间内对n个数据进行等概率随机抽取,例如:从1000个数据中等概率随机抽取出100个。另外,如果数据集合的量特别大或者还在增长(相当于未知数据集合总量),该算法依然可以等概率抽样。
1、如何随机从n个对象中选择一个对象?
【解法】:每次以1/m的概率选择是否将第m个数放入蓄水池。
【证明】:第m个数最终被选择的概率 = 选择第m个数*后面的数都不被选择,即
2、如何随机从n个对象中选择k个对象?
【解法】:每次以k/m的概率选择是否将第m个数放入蓄水池。
【证明】:第m个数最终被选择的概率 = 选择第m个数*(后面的数都不被选择+后面的数被选择但是不替换第m个数),即