文章目录

  • 一、线性同余法生成随机数
  • 二、洗牌算法
  • 三、蓄水池抽样
  • 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的概率,即:

随机数、洗牌算法、蓄水池抽样等问题_蓄水池抽样_02

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个数*后面的数都不被选择,即随机数、洗牌算法、蓄水池抽样等问题_随机数_03

随机数、洗牌算法、蓄水池抽样等问题_洗牌算法_04

2、如何随机从n个对象中选择k个对象?

【解法】:每次以k/m的概率选择是否将第m个数放入蓄水池

【证明】:第m个数最终被选择的概率 = 选择第m个数*(后面的数都不被选择+后面的数被选择但是不替换第m个数),即随机数、洗牌算法、蓄水池抽样等问题_随机数_05

随机数、洗牌算法、蓄水池抽样等问题_蓄水池抽样_06