【问题标题】:More efficient way to check neighbours in a two-dimensional array in Java在 Java 中检查二维数组中的邻居的更有效方法
【发布时间】:2011-05-06 10:58:34
【问题描述】:

大家好,对于我的一些大学作业,我发现需要检查二维数组(网格)中的相邻单元格。我使用的解决方案有点像使用异常的黑客攻击,我正在寻找一种方法来清理它,而不会像我的一些同学那样使用大量 if 语句。我目前的解决方案是

for ( int row = 0; row < grid.length; row++ ) {
    for ( int col = 0; col < grid.length; col++ ) {
        // this section will usually be in a function
        // checks neighbours of the current "cell"
        try {
            for ( int rowMod = -1; rowMod <= 1; rowMod++ ) {
                for ( int colMod = -1; colMod <= 1; colMod++ ) {
                    if ( someVar == grid[row+rowMod][col+colMod] ) {
                        // do something
                    }
                }
            }
        } catch ( ArrayIndexOutOfBoundsException e ) {
            // do nothing, continue
        }
        // end checking neighbours
    }
}

想到使用异常来使我的代码正常工作的原因,我不寒而栗,因此我正在寻找有关如何在不牺牲可读性的情况下从代码中消除对异常的依赖的建议,以及如何我可以使这个代码段通常更有效。提前致谢。

【问题讨论】:

  • 不要过多指责,但例外应该是一些例外。事先验证输入几乎总是更好,尤其是在琐碎的情况下。否则,您可能会掩盖重要的异常并隐藏算法的缺陷。
  • 我想摆脱异常的更多理由。同样,这只是完成任务的快速技巧,但我不满意就这样离开。

标签: java exception performance multidimensional-array


【解决方案1】:

你可以试试这个。 首先确定网格的大小让我们说它的 8 X 8 & 分配 MIN_X = 0, MIN_Y = 0, MAX_X =7, MAX_Y =7

你的当前位置由 thisPosX , thisPosY 表示,然后试试这个:

int startPosX = (thisPosX - 1 < MIN_X) ? thisPosX : thisPosX-1;
int startPosY = (thisPosY - 1 < MIN_Y) ? thisPosY : thisPosY-1;
int endPosX =   (thisPosX + 1 > MAX_X) ? thisPosX : thisPosX+1;
int endPosY =   (thisPosY + 1 > MAX_Y) ? thisPosY : thisPosY+1;


// See how many are alive
for (int rowNum=startPosX; rowNum<=endPosX; rowNum++) {
    for (int colNum=startPosY; colNum<=endPosY; colNum++) {
        // All the neighbors will be grid[rowNum][colNum]
    }
}

你可以在 2 个循环中完成它。

【讨论】:

  • 是的,我一直在考虑这个问题,我想我想出的最好的解决方案就是这样,除了我使用 Math.最大值和数学最小值。
【解决方案2】:

所以rowcol 当前包含我要检查其邻居的单元格的坐标。因此,如果我有一个名为START_OF_GRID 的类变量包含0,我的解决方案如下:

int rowStart  = Math.max( row - 1, START_OF_GRID   );
int rowFinish = Math.min( row + 1, grid.length - 1 );
int colStart  = Math.max( col - 1, START_OF_GRID   );
int colFinish = Math.min( col + 1, grid.length - 1 );

for ( int curRow = rowStart; curRow <= rowFinish; curRow++ ) {
    for ( int curCol = colStart; curCol <= colFinish; curCol++ ) {
        // do something
    }
}

【讨论】:

  • 出于某种原因(可能是我做错了),Vivek 的解决方案对我不起作用(它只检查 4 个单元格而不是 8 个)。你的工作正常!谢谢。
【解决方案3】:

为什么不能在数组访问前检查 row+rowMod 和 col+colMod 的有效性?

类似:

 r=row+rowMod;
 c=col+colMod;
 if (r < 0 || c < 0 || r >= grid.length || c >= grid.length) continue;

或者(没有继续):

 if (r >= 0 && c >= 0 && r < grid.length && c < grid.length && 
     someVar == grid[r][c]) { /* do something */ }

【讨论】:

  • 一个很好的解决方案,比我的效率高得多,但我仍然认为它有点老套,因为我学会了避免breakcontinue。非常感谢您的回答。
  • 如果您害怕继续,只需反转条件并将其添加到您的 if
  • 我真的很喜欢这个;它很小,不会超出范围。
【解决方案4】:

基本原则是不要访问越界的东西——所以要么保护边界,要么一开始就不要越界。也就是说,从一个不会立即出界的地方开始,在出界之前停下来。

for ( int row = 1; row < grid.length - 1; row++ ) {
    for ( int col = 1; col < grid.length - 1; col++ ) {
        // this section will usually be in a function
        // checks neighbours of the current "cell"
        for ( int rowMod = -1; rowMod <= 1; rowMod++ ) {
            for ( int colMod = -1; colMod <= 1; colMod++ ) {
                if ( someVar == grid[row+rowMod][col+colMod] ) {
                    // do something
                }
            }
        }
        // end checking neighbours
    }
}

与您当前的代码一样,这不一定能正确处理边缘条件 - 也就是说,它会在 3x3 网格适合矩阵的任何地方应用 3x3 网格,但不会将网格缩小为 2x2、2x3 或位于矩阵边缘时的 3x2 网格。但是,它将允许主体中的方法检查 3x3 网格来观察矩阵中的每个单元。

【讨论】:

  • 也称为“守卫”。通常,“保护”单元格(例如,第 0 列中的单元格)将包含一些特殊值,这将导致无操作或易于处理。
  • 是的,这将是一个解决方案,比如说,我的 ConnectFour 程序,我只是检查连接的邻居,但它不会在 GameOfLife 程序中正确计算邻居。我不需要检查每个单元格,而是找到每个单元格的邻居数(指定条件)。不过感谢您的回答。
【解决方案5】:

如果我正确理解了您的代码,并且正确猜测了您的顾虑,那么当感兴趣的单元格位于网格的一个边缘时,您会尝试避免检查不存在的邻居。一种可能适合您的应用程序也可能不适合您的应用程序的方法是在您的网格周围放置一个 1 单元格宽的边框。然后,您在这个扩展网格的内部运行循环,您检查的所有单元格都有 4 个邻居(如果计算对角相邻的单元格,则为 8 个)。

【讨论】:

  • 这与 Mark E 的解决方案相结合,将是一个完美的解决方案,谢谢。
【解决方案6】:

这个怎么样:

private static void printNeighbours(int row, int col, int[][] Data, int rowLen, int colLen)
{
    for(int nextR=row-1; nextR<=row+1; nextR++)
    {
        if(nextR<0 || nextR>=rowLen)
            continue;  //row out of bound
        for(int nextC=col-1; nextC<=col+1; nextC++)
        {
            if(nextC<0 || nextC>=colLen)
                continue;  //col out of bound
            if(nextR==row && nextC==col)
                continue;    //current cell
            System.out.println(Data[nextR][nextC]);
        }
    }
}

【讨论】:

    【解决方案7】:
    private void fun(char[][] mat, int i, int j){
        int[] ith = { 0, 1, 1, -1, 0, -1 ,-1, 1};
        int[] jth = { 1, 0, 1, 0, -1, -1 ,1,-1};
         // All neighbours of cell
         for (int k = 0; k < 8; k++) {
                if (isValid(i + ith[k], j + jth[k], mat.length)) {
                    //do something here 
                }
            }
    }
    
    private boolean isValid(int i, int j, int l) {
            if (i < 0 || j < 0 || i >= l || j >= l)
                return false;
            return true;
    }
    

    【讨论】:

    • 请在回答中添加一些描述。@Vikas Tiwari
    • 更新了代码。您可以使用 mat[i + ith[k]][j + jth[k]] 访问评论区域中的所有邻居。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    • 2010-10-13
    • 2013-04-08
    • 2017-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多