有没有更简单的方法来进行这项检查?

Is there a simpler way to do this check?

我要用随机数01填充一个矩阵,但是如果一个单元格包含1,它周围的其他8个必须是0。作为初学者,我试图以这种方式实现我的代码:

for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 5; j++) {
        a[i][j] = rand() % 2;
        if (a[i][j] == 1) {
            a[i-1][j-1] = 0; 
            a[i-1][j]   = 0; 
            a[i-1][j+1] = 0;
            a[i][j-1]   = 0; 
            a[i][j+1]   = 0;
            a[i+1][j+1] = 0; 
            a[i+1][j]   = 0; 
            a[i+1][j+1] = 0;
        }
    }
}

当然,我确信有更简单的方法来编写这段代码。你能帮助我吗?提前致谢!

我认为没有更简单或更简洁的方法来完成这项工作。您的代码清晰且尽可能简短。有一些替代方案具有更好的属性,例如不使 1 的外观偏向边缘,尤其是矩阵的右下角,但这是一个不同的标准。

正如我在评论中所写,您确实需要避免超出数组的边界(这会使您的代码更复杂一些),当然没有必要将 0 添加到您的随机数中。

您可以巧妙地通过以其他方式对矩阵进行编码,例如在unsigned char的数组中按位编码,但这不会更简单,也可能不更干净。

解决超限问题的一种非常简洁的方法可能是将数组的每个维度声明为大两个元素,并对实际元素使用基于一的索引。这将为实际数据的所有方面提供一个余量,这样您的所有写入都在实际数组的范围内,即使有些超出了有意义的数据。即:

int a[7][7] = {0};  // a[1][1] ... a[5][5] will contain the real data

for (int i = 1; i < 6; i++) {
    for (int j = 1; j < 6; j++) {
        a[i][j] = rand() % 2;
        if (a[i][j] == 1) {
            a[i-1][j-1] = 0; 
            // ...
        }
    }
}

您认为您生成的实际矩阵只是那些具有 1 <= i && i <= 51 <= j && j <= 5 的元素。那么,使用 i - 1j + 1 之类的索引并不重要,因为它们对真实数据的所有 ij 都有效.

您可能应该分两步完成,否则,您可以在之前擦除的单元格上再次写入 1。此外,您必须避免在矩阵之外书写。这是一个例子:

int main()
{
    // First fills the matrix :
    int a[5][5] = {0};
    printf("Random Matrix :\n");
    for (int i = 0; i < 5; i++){
        for (int j = 0; j < 5; j++){
            a[i][j] = rand() % 2;
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
    // Next filters it :
    printf("---------\nFiltered Matrix :\n");
    for (int i = 0; i < 5; i++){
        for (int j = 0; j < 5; j++){
            if (a[i][j] == 1) {
                if (i > 0) {
                    a[i-1][j]              = 0; 
                    if (j > 0) a[i-1][j-1] = 0;
                    if (j < 4) a[i-1][j+1] = 0;
                }
                if (i < 4) {
                    a[i+1][j]              = 0; 
                    if (j < 4) a[i+1][j+1] = 0;
                }
                if (j > 0) a[i][j-1] = 0; 
                if (j < 4) a[i][j+1] = 0; 
               
            }
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

输出

Random Matrix :
1 0 1 1 1 
1 0 0 1 1 
0 1 0 1 1 
0 0 0 0 0 
1 0 1 1 0 
---------
Filtered Matrix :
1 0 1 0 1 
0 0 0 0 0 
0 1 0 1 0 
0 0 0 0 0 
1 0 1 0 0 

一些想法

您的代码是循环中的循环。对于二维数组,您可以考虑在一个循环中完成所有操作。对于小型阵列,即:1-5 真的没关系。对于较大的数组,如果将 i,j 计算为数组的函数,则算法会更快。 参见:Map a 2D array onto a 1D array

您还可以将变量命名为 'a' 'i',j 类似于 row、col 或更有意义的名称,具体取决于代码的缩进目的。

另一部分让我有点困惑。假设您的阵列是 5x5 并且还假设您的最终目标是确保每个“1”总是有 8 零的邻居,一旦第一个随机数生成产生“1”并强制 8 个邻居为零,多达 4 个邻居不再需要更新。 (i,j+1)/(i+1,j)/(i+1,j+1)/(i-1,j)。正如@Weather Vane 所指出的,您正在覆盖您的工作,这可能是您获得 'redundant' 感觉的地方。

#define MAX_ARRAY 5


int in_bounds(int row,int col)
{
if (row >= MAX_ARRAY) return 0;
if (col >= MAX_ARRAY) return 0;
return 1;
}

void print_matrix (int matrix[MAX_ARRAY][MAX_ARRAY],int size)
{

for (int i=0;i<size;i++)
 {
 for (int j=0;j<size;j++)
  {
  fprintf(stdout,"%d",matrix[i][j]);
//  fprintf(stdout,"%d,%d ",i,j);
  }
 fprintf(stdout,"\n");

 }
}

int main()
{
//for stack overflow: 
   srand(time(0));
    int matrix[MAX_ARRAY][MAX_ARRAY];
     memset(matrix, -1, sizeof(int) * MAX_ARRAY * MAX_ARRAY);
  
    for (int counter=0;counter<MAX_ARRAY * MAX_ARRAY;counter++)
      {
      int col=counter / MAX_ARRAY;
      int row=counter % MAX_ARRAY;

      if (matrix[row][col] == -1)
        {
        matrix[row][col] = rand() %2;
        if (matrix[row][col] == 1)
         {
            if (in_bounds(row,col+1)) matrix[row][col+1] = 0;
            if (in_bounds(row+1,col)) matrix[row+1][col] = 0;
            if (in_bounds(row+1,col+1)) matrix[row+1][col+1] = 0;
            if (in_bounds(row-1,col)) matrix[row-1][col] = 0;
            if (in_bounds(col,row-1)) matrix[col][row-1] = 0;
            if (in_bounds(row-1,col-1)) matrix[row-1][col-1] = 0;
            if (in_bounds(row-1,col+1)) matrix[row-1][col+1] = 0;
            if (in_bounds(row+1,col-1)) matrix[row+1][col-1] = 0;
        }
       }

  }
print_matrix(matrix,MAX_ARRAY);
}    

您的代码有问题:您写入坐标在 0..4 范围之外的矩阵单元格。

这是修改后的版本:

for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 5; j++) {
        a[i][j] = 0;
        if (rand() % 2) {
            for (int ii = i - 1; i <= i + 1; i++) {
                if (ii >= 0 && ii < 5) {
                    for (jj = j - 1; j <= j + 1; j++) {
                        if (jj >= 0 && jj < 5)
                            a[ii][jj] = 0;
                    }
                }
            }
            a[i][j] = 1;
        }
    }
}

除了越界访问数组,你的程序没问题。这是一种更通用的方法,适用于大于 1 个单元格的范围

#include <stdio.h>
#include <stdlib.h>

#define ROW 5
#define COL 5
#define RAN 1 // range

int main() {

    int a[ROW][COL];
    
    for (int i = 0; i < ROW; i++) {
    
        for (int j = 0; j < COL; j++) {
        
            if( (a[i][j] = rand() % 2) ) {
                
                for(int k = i-RAN; k <= i+RAN && k < ROW; k++) {
                    
                    for(int l = j-RAN; l <= j+RAN && l < COL; l++) {
                        
                        if( k >= 0 && l >= 0 && !(k == i && l == j)) {
                            
                            a[k][l] = 0;
                        }
                    }
                }
            }
        }
    }
    
    for (int i = 0; i < ROW; i++) {
    
        for (int j = 0; j < COL; j++) {
            
            printf("%d ", a[i][j]);
        }
        puts("");
    }
    
    return 0;
}

有一种更简单的方法可以做到这一点:您需要使用曼哈顿公式。所以,代码可以是:

int distance = sqrt(pow((x1-x2),2) + pow((y1-y2),2))

其中 x1、y1 是我的单元格的坐标,x2、y2 是包含 1 的其他单元格的坐标。如果距离 < 1,则不能将单元格设置为 1。因此,您可以创建一个矩阵,其中包含包含 1 的所有单元格的坐标,并在将单元格设置为 1 之前检查整个矩阵。