C++ 中的水库抽样

17 Mar 2025 | 4 分钟阅读

本文旨在通过算法解释和代码示例,帮助您理解 C++ 中的蓄水池抽样。内容涵盖了蓄水池抽样的基础知识,一个实际用例,详细的算法解析,以及一个带有相应示例的 C++ 实现。

理解蓄水池抽样

蓄水池抽样是一系列随机算法,用于从 n 个数字的集合中进行无放回的随机抽样,选择 k 个数字,其中 n 可以是明确定义的,也可以是未定义的。本文将通过一个用例来解释该算法。

算法

在算法中,会创建一个大小为 k 的数组 reservoir[],以及一个大小为 n(未定义大小)的随机数集合。该过程包括从列表中选择一个随机数并将其放入 reservoir[] 列表中。需要注意的是,一旦一个项目被选中,它就不能被后续选中。算法的流程如下:

  1. 复制 reservoir 列表的前 k 个元素。
  2. 依次选择 (k+1) th 个数字之后的元素,并将其分配给索引 i。
  3. 生成一个从 0 到 i 的随机索引,并将其分配给 j。
  4. 如果 j 在 0 到 k 的范围内,则交换 reservoir[j] 和 array[i]。

C++ 实现示例

本文提供了蓄水池抽样算法的 C++ 实现,并附带一个代码片段来演示其应用。代码中包含用于显示数组的函数,以及通过蓄水池抽样算法从数组中选取 k 个元素的函数。

输出

Reservoir sampling in C++

由于每次编译时蓄水池都是随机化的,因此此代码的输出每次运行时都会有所不同。

与其他抽样方法的比较

虽然简单随机抽样很简单,但在数据集大小未知或过大而无法放入内存的情况下,蓄水池抽样则更为突出。与遵循固定模式的系统抽样不同,蓄水池抽样提供了实现均衡抽样所必需的不确定性。

在无法将大型数据集保留在内存中的情况下,蓄水池抽样通过处理数据就能很好地工作,使其成为流式处理和在线处理场景的首选。

应用

蓄水池抽样在各个领域都有应用。在数据流中,它能够有效地对顺序到达的数据点进行抽样,非常适合实时分析。随机算法利用蓄水池抽样进行近似计数和抽样等任务。在机器学习中,它在不将整个数据集存储在内存中的情况下,在创建代表性训练数据集方面发挥着作用。

效率和时间复杂度

蓄水池抽样的时间复杂度为 O(n),对于大型数据集来说非常高效。它能够在内存恒定的情况下提供无偏样本的能力,使其成为效率至关重要的场景下的一个有吸引力的选择。

蓄水池抽样的变体

蓄水池抽样的变体能够满足特定需求。加权蓄水池抽样为元素引入权重,改变它们被选中的可能性。分级蓄水池抽样将数据集分为几层,确保最终样本的每层都有代表性。

结论

本文最后总结了蓄水池抽样,并提供了包含各种算法的示例。阅读本教程后,读者预计将对蓄水池抽样有一个理性的理解。