我有一个庞大的整数链表(假设它的大小为N,但我不知道N)并希望在最短的时间/空间内从中获取k个随机值。
我认为必须有可能编写一个由内到外的Fisher-Yates shuffle变体来解决O(N)时间和O(k)额外空间中的这个问题。
任何人都可以帮助我获得具有指定时间/空间范围的统计上正确的解决方案吗?
我认为我目前的代码接近正确的解决方案:
public class Node
{
public int Data;
public Node Next;
// O(N) time, O(k) additional space
public int[] GetRandomData(int k)
{
var a = new int[k];
var rand = new Random();
int n = 0;
Node cur = this;
while (cur != null)
{
int r = rand.Next(0, n);
if (r < k)
{
a[r] = cur.Data;
}
cur = cur.Next;
}
if (n < k) throw new ArgumentException("k is bigger than N");
return a;
}
}
答案 0 :(得分:2)
这将返回来自未知长度序列的k个项目的均匀分布的随机样本。该算法称为reservoir sampling。
def sample(seq, k):
seq = iter(seq)
result = [seq.next() for _ in xrange(k)]
for i, s in enumerate(seq):
r = random.randrange(i + k + 1)
if r < k: result[r] = s
return result
答案 1 :(得分:0)
我最终得到了这个版本(C#),我很确定它是正确的。告诉我,如果我错了。
public class Node
{
public int Data;
public Node Next;
// O(N) time, O(k) additional space
public int[] GetRandomData(int k)
{
var a = new int[k];
var rand = new Random();
a[0] = this.Data;
int i = 1;
for (Node cur = this.Next; cur != null; cur = cur.Next, i = i + 1)
{
int r = rand.Next(0, i + 1);
if (r < k)
{
if (i < k)
{
a[i] = a[r];
}
a[r] = cur.Data;
}
}
if (i < k) throw new ArgumentException("k is bigger than N");
return a;
}
}
UPD:好的,所以我的代码与wikipedia中的代码相同,所以它必须在统计上正确。
答案 2 :(得分:-1)
这是sattolo算法的实现
from random import randrange
def sattoloCycle(items):
i = len(items)
while i > 1:
i = i - 1
j = randrange(i) # 0 <= j <= i-1
items[j], items[i] = items[i], items[j]
return