假设我有一个列表列表,如下所示:
因此外部列表的大小为3,内部列表的大小为5,3和4。
我需要得到任何内部列表的随机元素,给每个元素一个随机的机会。所以我可以编写一个算法:
0
和totalListsSize (5 + 3 + 4) = 12
之间生成随机广告,例如randomIndex 7
randomIndex 7 - firstListSize 5 = newRandomIndex 2
randomIndex 2 in secondList = element g
。问题在于顺序选择必须完整且可耗尽:在上面的示例中进行了12次连续选择后,我必须选择每个元素一次。
有没有办法可以扩展?
randomIndex
。答案 0 :(得分:8)
为什么不生成所有可能索引的排列(换句话说,您将对序列[0,12)进行随机排列)。然后你知道你将按照随机顺序一次性击中所有元素。
为了有效查找,您可以保持数组长度的运行总计。在你的例子中:0,5,8,12。这样你就可以进行二进制搜索,通过“总索引”找到任何数组。
答案 1 :(得分:1)
好吧,您可以创建一组可能的索引,随机选择其中一个索引,删除所选索引并访问相应的对象。
或者,正如您所说,您可以创建一个联合列表并从中选择,删除任何选定的元素。
这两种方法都需要一些初始化,但无论如何你都必须做一些书籍。
另一种方法可能是将所选索引存储在一个集合中,并在创建新的随机索引后,您可以检查新的索引是否已经在“已使用”集合中。但是,如果要选择整个池中较高的百分比,这种方法会变得越来越慢,因为您经常会使用已经使用过的索引。为了从大列表中仅选择一些,这种方法可能会更好,因为它不需要太多的初始化和内存。
答案 2 :(得分:0)
当您“弹出”它们时,是否可以从列表中删除元素?
如果是这样,你可以这样做:只需在选择它时从列表中删除一个元素,然后在计算下一个索引之前从总大小中减去一个元素,然后根据需要重复。
答案 3 :(得分:0)
我建议如下:
mark
,列出每个列表中选定的元素然后,确定哪个元素与您的randomIndex
对应:
List<List<Integer>> mark = // ... one mark list for each array
E[][] lists = // ... the lists you want to select random elements from
void selectAllElementsOnce( int totalElementCount ){
Random r = new Random();
for(int selected = 0; selected < totalElementCount; selected++){
E element = this.elementForRandomIndex(r.nextInt(totalElementCount - selected));
// do something with this element
}
}
E elementForRandomIndex( int randomIndex ) {
for(int i = 0; i < lists.length; i++ ) {
if(randomIndex < lists[i].length - mark.get( i ).size()) {
int j = 0;
while(mark.get( i ).size() > j && mark.get( i ).get( j ) <= randomIndex) {
randomIndex++ ;
j++ ;
}
mark.get( i ).add( j, randomIndex );
return lists[i][randomIndex];
} else {
randomIndex -= lists[i].length - mark.get( i ).size();
}
}
throw new IndexOutOfBoundsException();
}
该解决方案的复杂性在于O(numberOfLists + maximumListSize),用于标记列表的实现,其在恒定时间内提供元素访问(例如,ArrayList)。请注意,它不是两个术语的乘积,因为只迭代了一个列表。
答案 4 :(得分:0)
使用以下课程:
import java.util.Enumeration;
import java.util.Random;
public class RandomPermuteIterator implements Enumeration<Long> {
int c = 1013904223, a = 1664525;
long seed, N, m, next;
boolean hasNext = true;
public RandomPermuteIterator(long N) throws Exception {
if (N <= 0 || N > Math.pow(2, 62)) throw new Exception("Unsupported size: " + N);
this.N = N;
m = (long) Math.pow(2, Math.ceil(Math.log(N) / Math.log(2)));
next = seed = new Random().nextInt((int) Math.min(N, Integer.MAX_VALUE));
}
public static void main(String[] args) throws Exception {
RandomPermuteIterator r = new RandomPermuteIterator(100);
while (r.hasMoreElements()) System.out.print(r.nextElement() + " ");
}
@Override
public boolean hasMoreElements() {
return hasNext;
}
@Override
public Long nextElement() {
next = (a * next + c) % m;
while (next >= N) next = (a * next + c) % m;
if (next == seed) hasNext = false;
return next;
}
}