水塘抽样
一、一般的抽样算法
对于数据流中的数据,我们将其存储到容器中,并使用随机数取出[0, n)的任意一个元素,完成等概率抽样。
该算法的时间与空间复杂度均为O(n)。
- 优点:简单易实现
- 缺点:数据量过大时,将所有数据存入容器会有内存溢出问题。
二、水塘抽样算法
水塘抽样算法用于:在数据流中以O(n)的时间复杂度和O(1)的空间复杂度完成等概率抽样。
1、抽样过程
对于数据流中的第i个数,它有 1/i 的概率被替换为本轮随机抽样的结果:
int ans = 0;
for (int i = 1; i <= n; ++i)
{
if (rand() % i == 0) // 1/i的概率
ans = array[i];
}
return ans;
2、等概率证明
水塘抽样的算法实现也非常简单,现在给出其证明过程:
假设第i个值被抽取,则[i+1, n]都没有被抽取,即:
P
(
第
i
个被抽取
)
=
1
/
i
∗
P
(
第
i
+
1
个没被抽取
)
∗
.
.
.
∗
P
(
第
n
个没被抽取
)
=
1
/
i
∗
i
/
(
i
+
1
)
∗
(
i
+
1
)
/
(
i
+
2
)
∗
.
.
.
∗
(
n
−
1
)
/
n
=
1
/
n
\begin{align} P(第i个被抽取)&=1/i * P(第i+1个没被抽取) * ...* P(第n个没被抽取)\\ &=1/i*i/(i+1)*(i+1)/(i+2)*...*(n-1)/n\\ &=1/n \end{align}
P(第i个被抽取)=1/i∗P(第i+1个没被抽取)∗...∗P(第n个没被抽取)=1/i∗i/(i+1)∗(i+1)/(i+2)∗...∗(n−1)/n=1/n
3、水塘抽样的优势
- 不需要预先知道数据总量为多少。
- 空间复杂度为O(1)。