# 【算法34】蓄水池抽样算法 (Reservoir Sampling Algorithm)

## 蓄水池抽样算法简介

 1 array R[k];    // result
2 integer i, j;
3
4 // fill the reservoir array
5 for each i in 1 to k do
6     R[i] := S[i]
7 done;
8
9 // replace elements with gradually decreasing probability
10 for each i in k+1 to length(S) do
11     j := random(1, i);   // important: inclusive range
12     if j <= k then
13         R[j] := S[i]
14     fi
15 done

## 算法的C++实现

 1 #include <iostream>
2 #include <string>
3 #include <vector>
4 #include <cassert>
5 #include <cstdio>
6 #include <cstdlib>
7 #include <ctime>
8 using namespace std;
9
10 /**
11  * Reservoir Sampling Algorithm
12  *
13  * Description: Randomly choose k elements from n elements ( n usually is large
14  *              enough so that the full n elements may not fill into main memory)
15  * Parameters:
16  *      v - the original array with n elements
17  *      n - the length of v
18  *      k - the number of choosen elements
19  *
20  * Returns:
21  *      An array with k elements choosen from v
22  *
23  * Assert:
24  *      k <= n
25  *
26  * Author:  python27
27  * Date:    2015/07/14
28  */
29 vector<int> ReservoirSampling(vector<int> v, int n, int k)
30 {
31     assert(v.size() == n && k <= n);
32
33     // init: fill the first k elems into reservoir
34     vector<int> reservoirArray(v.begin(), v.begin() + k);
35
36     int i = 0;
37     int j = 0;
38     // start from the (k+1)th element to replace
39     for (i = k; i < n; ++i)
40     {
41         j = rand() % (i + 1); // inclusive range [0, i]
42         if (j < k)
43         {
44             reservoirArray[j] = v[i];
45         }
46     }
47
48     return reservoirArray;
49 }
50
51
52 int main()
53 {
54     vector<int> v(10, 0);
55     for (int i = 0; i < 10; ++i) v[i] = i + 1;
56
57     srand((unsigned int)time(NULL));
58     // test algorithm RUN_COUNT times
59     const int RUN_COUNT = 10000;
60     int cnt[11] = {0};
61     for (int k = 1; k <= RUN_COUNT; ++k)
62     {
63         cout << "Running Count " << k << endl;
64
65         vector<int> samples = ReservoirSampling(v, 10, 5);
66
67         for (size_t i = 0; i <samples.size(); ++i)
68         {
69             cout << samples[i] << " ";
70             cnt[samples[i]]++;
71         }
72         cout << endl;
73     }
74
75     // output frequency stats
76     cout << "*************************" << endl;
77     cout << "Frequency Stats" << endl;
78     for (int num = 1; num < 11; ++num)
79     {
80         cout << num << " : \t" << cnt[num] << endl;
81     }
82     cout << "*************************" << endl;
83
84     return 0;
85 }

## 参考文献

【1】 Wikipedia：Reservoir Sampling

posted @ 2015-07-14 22:50  python27  阅读(9716)  评论(0编辑  收藏  举报