参考原文链接:
https://blog.csdn.net/qq_25026989/article/details/89512769
问题描述:
洗牌算法是将原来的数组进行打散,使原数组的某个数在打散后的数组中的每个位置上等概率的出现。
主要有3中经典的洗牌算法:
1.
抽牌
:
1.初始化原始数组和新数组,原始数组长度为n(已知);
2.从还没处理的数组(假如还剩k个)中,随机产生一个[0, k)之间的数字p(假设数组从0开始);
3.从剩下的k个数中把第p个数取出;
4.重复步骤2和3直到数字全部取完;
5.从步骤3取出的数字序列便是一个打乱了的数列。
时间复杂度为O(n*n),空间复杂度为O(n).
2.
换牌
(
原地打乱顺序
):
1. 建立一个数组大小为 n 的数组 arr,分别存放 1 到 n 的数值;
2. 生成一个从 0 到 n – 1 的随机数 x;
3. 输出 arr 下标为 x 的数值,即为第一个随机数;
4. 将 arr 的尾元素和下标为 x 的元素互换;
5. 同2,生成一个从 0 到 n – 2 的随机数 x;
6. 输出 arr 下标为 x 的数值,为第二个随机数;
7. 将 arr 的倒数第二个元素和下标为 x 的元素互换;
……
如上,直到输出 m 个数为止
时间复杂度为O(n),空间复杂度为O(1)
缺点必须知道数组长度n.原始数组被修改了,这是一个原地打乱顺序的算法,算法时间复杂度也从Fisher算法的 O(n2)提 升到了O(n)。由于是从后往前扫描,无法处理不知道长度或动态增长的数组。
3.
插牌
(蓄水池抽样):
1.先选中第1到k个元素,作为被选中的元素。然后依次对第k+1至第N个元素做如下操作:
2.每个元素都有k/x的概率被选中,然后等概率的(1/k)替换掉被选中的元素。其中x是元素的序号。
从N个元素中随机等概率取出k个元素(洗牌发牌可以认为k=1),N长度未知。
在o(n)时间内对n个数据进行等概率随机 抽取
。如果数据集合的量特别大或者还在增长(相当于未知数据集合总量),该算法依然可以等概率抽样.