【问题标题】:Get adjacent elements in a two-dimensional array?获取二维数组中的相邻元素?
【发布时间】:2011-01-03 09:06:10
【问题描述】:

我有一个二维数组,比如说

0 0 0 0 0
0 2 3 4 0
0 9 1 5 0
0 8 7 6 0
0 0 0 0 0

我需要得到所有与1相邻的数字(2、3、4、5、6、7、8、9)

有没有比以下更丑的解决方案:

topLeft = array[x-1][y-1]
top  = array[x][y-1]
topRight = array[x+1][y-1]
# etc

谢谢!

【问题讨论】:

    标签: algorithm arrays language-agnostic matrix multidimensional-array


    【解决方案1】:
    #include <iostream>
    using namespace std;
    
    bool isValidPos(int i, int j, int n)
    {
        if (i < 0 || j < 0 || i > n - 1 || j > n - 1)
            return 0;
    
        return 1;
    }
    
    void adjacentElements(int arr[][3], int i, int j)
    {
        int n = 3;
        // first row
        if (isValidPos(i - 1, j - 1, n))
            cout << i - 1 << j - 1 << " ";
        if (isValidPos(i - 1, j, n))
            cout << i - 1 << j << " ";
        if (isValidPos(i - 1, j + 1, n))
            cout << i - 1 << j + 1 << " ";
        // second row
        if (isValidPos(i, j - 1, n))
            cout << i << j - 1 << " ";
        if (isValidPos(i, j + 1, n))
            cout << i << j + 1 << " ";
        // third row
        if (isValidPos(i + 1, j - 1, n))
            cout << i + 1 << j - 1 << " ";
        if (isValidPos(i + 1, j, n))
            cout << i + 1 << j << " ";
        if (isValidPos(i + 1, j + 1, n))
            cout << i + 1 << j + 1 << " ";
    }
    
    int main()
    {
        int arr[3][3] = {0};
    
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
    
                cout << i << j << " "
                     << " = [ ";
                adjacentElements(arr, i, j);
                cout << "]" << endl;
            }
            // cout << endl;
        }
    }
    

    输出

    00  = [ 01 10 11 ]
    01  = [ 00 02 10 11 12 ]
    02  = [ 01 11 12 ]
    10  = [ 00 01 11 20 21 ]
    11  = [ 00 01 02 10 12 20 21 22 ]
    12  = [ 01 02 11 21 22 ]
    20  = [ 10 11 21 ]
    21  = [ 10 11 12 20 22 ]
    22  = [ 11 12 21 ]
    

    【讨论】:

    • 在c++中输出矩阵中特定位置的相邻位置
    【解决方案2】:

    python 生成器获取给定 matirx 中的相邻节点

    def gen_adjacent_node(matrix_2d, node=(0,0)):
        rows = len(matrix_2d)
        columns = len(matrix_2d[0])
        for r in [-1, 0, 1]:
            for c in [-1, 0, 1]:
                if r == c == 0:
                    continue
                # check valid index
                if 0 <= node[0]+r < rows and 0 <= node[1]+c < columns:
                    # print((node[0]+i, node[1]+j))
                    yield (node[0]+r, node[1]+c)
    

    【讨论】:

    • 由于yield 是一个特定于python 的运算符,您可能还包括一个如何使用/打印此函数结果的示例?
    【解决方案3】:

    这是一个 Ruby 解决方案。即使对于不熟悉 Ruby 的读者,该算法也应该是显而易见的。请注意我是如何计算要迭代的行和列的(在大多数语言中都会类似地编写)。在我看来,对于要迭代的行的索引,这比“从max(r-1, 0)min(r+1, arr.size-1)”要干净得多。

    def adjacent(arr, r, c)
      rows_ndx = arr.each_index.select { |i| (i-r).abs < 2 }
      cols_ndx = arr.first.size.times.select { |j| (j-c).abs < 2 }
      rows_ndx.each_with_object([]) do |i,a| 
        cols_ndx.each { |j| a << arr[i][j] unless [i,j] == [r,c] }
      end
    end
    
    arr = [
      [-1,  2,  3,  4],
      [-2,  9,  1,  5],
      [-3,  8,  7,  6],
      [-4, -5, -6, -7]
    ]
    
    (0..2).each do |i|
      (0..3).each do |j|
        puts "adjacent to #{arr[i][j]} at r=#{i}, c=#{j} = #{adjacent(arr, i, j)}"
      end
    end
    

    打印

    adjacent to -1 at r=0, c=0 = [2, -2, 9]
    adjacent to  2 at r=0, c=1 = [-1, 3, -2, 9, 1]
    adjacent to  3 at r=0, c=2 = [2, 4, 9, 1, 5]
    adjacent to  4 at r=0, c=3 = [3, 1, 5]
    adjacent to -2 at r=1, c=0 = [-1, 2, 9, -3, 8]
    adjacent to  9 at r=1, c=1 = [-1, 2, 3, -2, 1, -3, 8, 7]
    adjacent to  1 at r=1, c=2 = [2, 3, 4, 9, 5, 8, 7, 6]
    adjacent to  5 at r=1, c=3 = [3, 4, 1, 7, 6]
    adjacent to -3 at r=2, c=0 = [-2, 9, 8, -4, -5]
    adjacent to  8 at r=2, c=1 = [-2, 9, 1, -3, 7, -4, -5, -6]
    adjacent to  7 at r=2, c=2 = [9, 1, 5, 8, 6, -5, -6, -7]
    adjacent to  6 at r=2, c=3 = [1, 5, 7, -6, -7]
    

    【讨论】:

      【解决方案4】:

      C++ 中可能如下所示:

      vector<int> adj;
      for (int i = 0; i < 9; i++)
        if (i != 4) adj.push_back(array[x + i/3 - 1][y + i%3 - 1]);
      

      这不是很明确的解决方案,但很短。

      【讨论】:

      • 该解决方案根本无法概括
      【解决方案5】:

      就个人而言,循环比原来的更丑。

      topLeft  = array[ x - 1 ][ y - 1 ]
      top      = array[ x     ][ y - 1 ]
      topRight = array[ x + 1 ][ y - 1 ]
      
      midLeft  = array[ x - 1 ][ y     ]
      midRight = array[ x + 1 ][ y     ]
      
      botLeft  = array[ x - 1 ][ y + 1 ]
      bot      = array[ x     ][ y + 1 ]
      botRight = array[ x + 1 ][ y + 1 ]
      

      但没有指定您想要的值 - 您在不同方向上所做的事情意味着您是否想要单独变量中的值。

      对于生活方式的游戏处理,您通常希望处理位模式而不是单个值的数组,并且您可以使用累加器和临时对象一次仅检查八个单元中的三个进行水平扫描。对于图形卷积,请使用具有 3x3 内核的现有库。

      处理边界的另一种方法是在每个方向上将数组扩展一个单元格。这避免了卷积代码中昂贵的分支。

      【讨论】:

      • 在搜索其他内容时,我偶然发现了您的答案。非常好的解决方案。我想知道......如果数组像帕斯卡金字塔,是否可以应用类似的东西?不是“一个”帕斯卡金字塔,只是形状:顶部一个,中间两个,底部三个?
      【解决方案6】:

      我可能会为每个方向寻找一个恒定的 dx、dy 列表,如下所示:

      struct {
          int dx;
          int dy;
      } directions[] = {{-1,-1,},{-1,0,},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
      

      然后你会使用一个简单的循环来迭代方向:

      for (int i = 0; i < 8; i++) {
          // use x + directions[i].dx;
          // use y + directions[i].dy;
      }
      

      您当然可以使用sizeof(directions) / sizeof(directions[1]) 代替上面的8

      【讨论】:

      • 这可能是最好看的实现
      • 嗨,xy 会在这里吗?谢谢。
      • 这是干净的,但添加边界检查后,它可能一样干净。
      【解决方案7】:

      如果你不担心顺序,最干净的可能是使用几个循环:

      result = new List<int>(8);
      for (dx = -1; dx <= 1; ++dx) {
          for (dy = -1; dy <= 1; ++dy) {
              if (dx != 0 || dy != 0) {
                  result.Add(array[x + dx][y + dy]);
              }
          }
      }
      

      如果顺序很重要,您可以按照您想要的顺序构建所有 (dx, dy) 的列表,然后对其进行迭代。

      正如 cmets 中所指出的,您可能想要添加边界检查。你可以这样做(假设顺序无关紧要):

      List<int> result = new List<int>(8);
      for (int dx = (x > 0 ? -1 : 0); dx <= (x < max_x ? 1 : 0); ++dx)
      {
          for (int dy = (y > 0 ? -1 : 0); dy <= (y < max_y ? 1 : 0); ++dy)
          {
              if (dx != 0 || dy != 0)
              {
                  result.Add(array[x + dx][y + dy]);
              }
          }
      }
      

      【讨论】:

      • 您需要考虑边缘情况。如果 (x, y) 的规范是 (0, 0) 那么您的数组索引将超出范围。由于这看起来像 C# 代码,这意味着你会得到一个异常。
      • 如果你把边界拉出来,它可以变得更干净。 dxmin = x > 0 ? -1:0; dxmax = x
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-12
      • 1970-01-01
      • 2011-07-27
      • 2015-12-26
      • 1970-01-01
      • 2012-09-10
      • 2021-10-28
      相关资源
      最近更新 更多