是否有一个简洁的算法可用于填充 m 号的巨大2D n x n 数组中的随机位置没有填充占用位置的整数? 和
的位置有点像伪代码:
int n;
int m;
void init(int new_n, int new_m) {
n = new_n;
m = new_m;
}
void create_grid() {
int grid[n][n];
int x, y;
for(x = 1; x <= n; x ++) {
for(y = 1; y <= n; y ++) {
grid[x][y] = 0;
}
}
populate_grid(grid);
}
void populate_grid(int grid[][]) {
int i = 1;
int x, y;
while(i <= m) {
x = get_pos();
y = get_pos();
if(grid[x][y] == 0) {
grid[x][y] = i;
i ++;
}
}
}
int get_pos() {
return random() % n + 1;
}
......但对于更大的n和m更有效率。特别是如果m越大并且占据的位置越多,生成一个不被占用的随机位置需要更长的时间。
答案 0 :(得分:0)
除非填充因子真的变大,否则你不必担心撞到占用位置。
假设例如已经填充了一半的细胞,那么你有50%的机会首先击中一个已填充的细胞;和25%连续击中两个填充的; 12.5%命中三个......平均而言,需要两次尝试才能找到空位! (更一般地说,如果只有1 / M的空闲单元,平均尝试次数会增加到M。)
如果您绝对不想测试单元格,可以使用自由单元格的索引初始化数组。然后,不是选择随机单元格,而是在数组中选择一个随机条目,介于1和L之间(列表的长度,最初为N²)。
选择条目后,设置相应的单元格,将列表中的最后一个元素移动到随机位置,并设置L = L-1。这样,自由职位列表就会保持最新状态。
请注意,此过程的效率可能低于盲目尝试。
答案 1 :(得分:0)
要生成没有重复的伪随机位置,您可以执行以下操作:
for (int y=0; y<n; ++y) {
for(int x=0; x<n; ++x) {
int u=x,v=y;
u = (u+hash(v))%n;
v = (v+hash(u))%n;
u = (u+hash(v))%n;
output(u,v);
}
}
为了使其正常工作,hash(x)需要是一个很好的伪随机散列函数,它产生的正数在你添加0到n之间的数字时不会溢出。
这是Feistel结构(https://en.wikipedia.org/wiki/Feistel_cipher)的一个版本,通常用于制作DES等加密密码。
诀窍是像u = (u+hash(v))%n;
这样的每一步都是可逆的 - 你可以通过u
来恢复原来的u = (u-hash(v))%n
(我的意思是你可以 %
运算符按照每个人的意愿使用负数进行处理)
由于您可以反转操作以从每个x,y
输出中获取原始u,v
,因此每个不同的x,y
必须生成不同的u,v
。