我正在编写一个三维元胞自动机。我现在在每一代中迭代它的方式是:
以下是代码:
我有一个简单的3整数结构
public class Coordinate
{
public int x;
public int y;
public int z;
public Coordinate(int x, int y, int z) {this.x = x; this.y = y; this.z = z;}
}
然后在某些时候我这样做:
List<Coordinate> all_coordinates = new ArrayList<>();
[...]
for(int z=0 ; z<length ; z++)
{
for(int x=0 ; x<diameter ; x++)
{
for(int y=0 ; y<diameter ; y++)
{
all_coordinates.add(new Coordinate(x,y,z));
}
}
}
然后在主算法中我这样做:
private void next_generation()
{
Collections.shuffle(all_coordinates);
for (int i=0 ; i < all_coordinates.size() ; i++)
{
[...]
}
}
问题是,一旦自动机变得太大,包含所有可能点的列表就会变得很大。我需要一种方法来对所有点进行洗牌,而不必将所有可能的点存储在内存中。我应该怎么做呢?
答案 0 :(得分:3)
执行此操作的一种方法是首先将三维坐标映射到单个维度。假设您的三维尺寸为X,Y和Z.因此您的x坐标从0到X-1等等。您的空间的完整大小为X*Y*Z
。我们称之为S
。
要将3空格中的任何坐标映射到1空格,请使用公式(x*X) + (Y*y) + z
。
当然,一旦你生成数字,你必须转换回3空间。这是扭转上述转换的简单问题。假设coord
是1空格坐标:
x = coord/X
coord = coord % X
y = coord/Y
z = coord % Y
现在,只需使用一个维度,您就可以将问题简化为以伪随机顺序生成从0到S的所有数字,而不会重复。
我至少知道三种方法。最简单的使用multiplicative inverse,如我在此处所示:Given a number, produce another random number that is the same every time and distinct from all other results。
当您生成了所有数字后,您可以通过为乘法逆计算选择不同的x
和m
值来“重新洗牌”列表。
在特定范围内创建非重复伪随机序列的另一种方法是使用linear feedback shift register。我没有一个现成的例子,但我已经使用过它们了。要更改顺序(即重新随机播放),请使用不同的参数重新初始化生成器。
您可能也对此问题的答案感兴趣:Unique (non-repeating) random numbers in O(1)?。该用户只需要查找1,000个号码,因此他可以使用表格,并且接受的答案反映了这一点。其他答案涵盖了LFSR,以及设计了特定时期的Linear congruential generator。
我提到的所有方法都没有要求你保持很多状态。无论您的范围是20还是20,000,000,您需要维护的状态量都是不变的。
请注意,我上面提到的所有方法都提供了伪随机序列。它们不是真正的随机,但它们可能足够接近随机以满足您的需求。