你好,基于油藏采样算法的weki描述,我这样做了,似乎没有按预期工作。算法在这里: http://en.wikipedia.org/wiki/Reservoir_sampling
哪里可能错了?
public int[] sample(int k, int[] array) {
int[] reservior = new int[k];
int i;
for(i=0; i<k; i++){
reservior[i] = array[i];
}
int j=0;
Random random = new Random(System.currentTimeMillis());
for(; i<array.length; i++){
j = random.nextInt(i);
if(j< k){
reservior[j] = array[i];
}
}
return reservior;
}
这是我的测试代码。我创建了一个包含0 ... 9元素的数组,并调用函数&#34; sample(k,array)&#34; K = 5。其中一个看起来如下。显然,它不是随机的,具有相同的概率。
0 9 2 3 5
0 9 2 3 5
0 6 8 7 4
0 6 8 7 4
0 6 8 7 4
0 6 8 7 4
0 6 8 7 4
0 6 8 7 4
0 6 8 7 4
0 6 8 7 4
int size = 10;
int[] array = new int[size];
for(int i=0; i<size; i++){
array[i] = i;
}
int k = 5;
for(int i=0; i<10; i++){
int[] reservior = sample(k, array);
for(int j=0; j<reservior.length; j++){
System.out.print(reservior[j] + " ");
}
System.out.println();
}
答案 0 :(得分:0)
System.currentTimeMillis()
返回相同的值超过一毫秒(通常在Windows机器上为10毫秒)。
Random是一个伪随机生成器。因此,如果您创建一个Random并使用给定值对其进行种子处理,它将给出一个确定的值序列。由于您总是重新创建它并使用相同的值对其进行播种,因此您始终会获得相同的值序列。
使用Random的唯一实例,创建一次,而不是种子。
答案 1 :(得分:0)
您正在快速调用样本,以便在几次运行中以相同的值播种。这就是为什么你看到价值最终会发生变化的原因,而不是每次通话。
您可以随机设置一个私有类变量,以便它只播种一次(并且您不需要自己播种...默认情况下它会使用System.nanoTime(),这会使更少< / i>一个问题本身)。这个解决方案还节省了一点内存,并且不必要地初始化一个新的Random实例花费了一些CPU周期。
public class ReservoirExample {
private Random random = new Random();
public int[] sample(int k, int[] array) {
int[] reservior = new int[k];
int i;
for(i=0; i<k; i++){
reservior[i] = array[i];
}
int j=0;
for(; i<array.length; i++){
j = random.nextInt(i);
if(j< k){
reservior[j] = array[i];
}
}
return reservior;
}
}
答案 2 :(得分:0)
谢谢,按照上面的建议,我运行样本()10000次,并得到这些数字。第一列是整数,第二列表示在函数的1000次调用中对此整数进行采样的次数。它似乎仍然不是均匀分布的数组中整数的随机采样。
我不确定算法的实现是否存在某些问题或其他问题。
1 4445
2 4390
3 4548
4 4435
5 5588
6 5505
7 5560
8 5553
9 5559