在巨大的2D阵列中填充随机位置

时间:2016-02-15 21:46:14

标签: arrays algorithm 2d

是否有一个简洁的算法可用于填充 m 号的巨大2D n x n 数组中的随机位置没有填充占用位置的整数? nformulamformula

的位置

有点像伪代码:

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越大并且占据的位置越多,生成一个不被占用的随机位置需要更长的时间。

2 个答案:

答案 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