【问题标题】:Reservoir Sampling Algorithm油藏采样算法
【发布时间】:2013-01-20 21:23:02
【问题描述】:

我想了解水库采样算法,我们从给定的 S 元素集合中选择 k 个元素,使得 k

在 wiki 上给出的算法中:

array R[k];    // result
integer i, j;

 // fill the reservoir array

for each i in 1 to k do
    R[i] := S[i]
done;

// replace elements with gradually decreasing probability

for each i in k+1 to length(S) do
    j := random(1, i);   // important: inclusive range
    if j <= k then
        R[j] := S[i]
    fi
done

如果我理解正确的话,我们首先从集合中选择k个元素,然后不断解析S的i个元素,生成1到i范围内的随机no j,并将元素j替换为S[i]。

如果要采样的集合 K 非常大,看起来很好,但是如果我想从无限大小(至少未知大小)的链表中随机选择 1 个元素,我将如何使用此算法...?

【问题讨论】:

    标签: java algorithm random reservoir-sampling


    【解决方案1】:

    水库采样算法适用于任何大小的链表,即使是事先未知长度的链表。事实上,水库采样的主要卖点之一是它适用于预先不知道大小的数据流。

    如果您设置 k = 1,然后运行正常的水库采样算法,那么您应该正确地从列表中获取一个均匀随机的元素。

    希望这会有所帮助!

    【讨论】:

    • 感谢您的评论,但它没有帮助...你能解释一下如何...?
    • @ASingh- 只需在您的链表上运行正常的水库采样算法,将 k 设置为 1。水库采样算法中的任何内容都不需要您提前知道列表的长度(您的 for 循环已经写到循环到length(S) 可以很容易地被一个while 循环替换,该循环在有未访问的元素时循环),所以你可以在未知长度的链表上运行算法。这有意义吗?
    • 是的,现在说得通了……谢谢
    【解决方案2】:

    我已经实现了一个不同的算法来解决这个问题,这是我的代码

    static char[] solution2(String stream, int K) {
        HashSet<Integer> set = new HashSet();
        char[] list = new char[K];
        stream = stream.concat(stream2);
        Random ran = new Random();
        for (int i = 0; i < K; i++) {
            int y = ran.nextInt(stream.length());
            if (set.add(y)) {
                list[i] = stream.charAt(y);
            } else {
                i--; //skip this iteration since its duplicate number
            }
        }
        return list;
    }
    

    无需遍历所有流值,只需选择一个随机值 J 并从流中获取 N[J]。

    【讨论】:

      猜你喜欢
      • 2016-05-21
      • 2014-08-02
      • 2013-05-11
      • 2011-09-02
      • 2015-05-13
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 2019-04-09
      相关资源
      最近更新 更多