我想实现对具有N个数字的特定集合的统一随机访问,就像集合中的每个项目将以均匀的1 / N机会访问。我把所有项目都放在一个修改过的双链表中。然后循环移动它随机时间,删除最后一项,然后添加为第一项。最后选择第一项。我用它来测试在没有将项目移出列表的情况下覆盖所有项目所需的调用次数。所需的矿山总数一直低于预期。想知道实现是否真的是随机的?你认为我的实现是真的随机吗?我已经调试了很长一段时间了,仍然没有任何线索。
public Item callout(){
for (int j=0; j<StdRandom.uniform(N); j++)
{
this.addFirst(this.removeLast());
// circular shift the queue by StdRandom.uniform(N)times, always return the first item;
}
return first.item;
}
public void addFirst(Item item){
Node<Item> oldfirst = first;
first = new Node<Item>();
first.item = item;
first.previous = null;
if (last == null)
{last = first; first.next = null;} //if it's the first element added. if last.next = null == last = null;!!!!
else
{
first.next = oldfirst;
oldfirst.previous = first;
}
N++;
}
public Item removeLast(){
if (last == null) throw new RuntimeException();
Item item = last.item;
// if right now only one element exists in the container
if (first == last)
{
first=null;
last=null;
}
else{
last =last.previous;
last.next = null;
// old first becomes first; optional operation, easy way to tell if it's the header.
}
N--;
return item;
}
以下类计算到达全面调用所需的调用次数,它接收一个包含n个项目的RandomCollection。基本上,它是一个带有1-N整数的集合,我使用一个数组int [] of flag来标记该项是否曾被调用过。
private static int getNumberOfCallsForComprehensiveCallout(RandomCollection<Integer> test, int n){
// create an array of the same number of items in collection, each with a Flag indicating whether it has beeen called
int calltimes =0; // calltimes stands for the numofcalls needed to reach a comprehensive call
int flag = 1; // flag used to indicate if this item has been called
int [] c = new int [n];
Arrays.fill(c, flag);
int NumberOfFlags = n;
while(NumberOfFlags != 0){
int numbercalled = test.callout();
if (c[numbercalled-1]==1) {NumberOfFlags--; c[numbercalled-1]=0;}
else; // indicate this item has been called earlier.
calltimes++;
// System.out.println(calltimes);
}
return calltimes; // return the number of calls for comprehensive callout each time this method is called.
}
答案 0 :(得分:1)
整体逻辑似乎是正确的,但是 -
首先,覆盖所有项目(替换)的调用次数可能大于集合的大小。事实上,大部分时间都会更大。
其次,在callout()
中,只在循环之外调用StdRandom.uniform(N)
方法。尝试以下更改 -
public Item callout(){
int randomRotate = StdRandom.uniform(N);
for (int j = 0; j < randomRotate; j++)
{
this.addFirst(this.removeLast());
}
return first.item;
}
我运行了一些模拟,如果在StdRandom.uniform(N)
循环内调用for
,则旋转次数不均匀分布。大小为10的集合的直方图结果 -
0 1 2 3 4 5 6 7 8 9
1001 1813 2074 2043 1528 902 454 144 37 4