【问题标题】:Rotating a two dimensional array by 90 degrees将二维数组旋转 90 度
【发布时间】:2011-06-01 12:52:50
【问题描述】:

我正在研究这段关于旋转 NxN 矩阵的代码;我已经无数次地跟踪了这个程序,我有点理解实际的轮换是如何发生的。它基本上先旋转角,然后按顺时针方向旋转角后的元素。我只是不明白几行代码,可以这么说,代码仍然没有在我的大脑中“驱动回家”。请帮忙。我将它旋转 90 度,给定一个 4x4 矩阵作为我的跟踪示例。

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

变成

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

public static void rotate(int[][] matrix, int n){
  for(int layer=0; layer < n/2; ++layer) {
     int first=layer; //It moves from the outside in. 
     int last=n-1-layer; //<--This I do not understand  
     for(int i=first; i<last;++i){
       int offset=i-first; //<--A bit confusing for me

       //save the top left of the matrix 
       int top = matrix[first][i];

       //shift left to top; 
       matrix[first][i]=matrix[last-offset][first]; 
       /*I understand that it needs
        last-offset so that it will go up the column in the matrix,
       and first signifies it's in the first column*/

       //shift bottom to left 
       matrix[last-offset][first]=matrix[last][last-offset];
        /*I understand that it needs
        last-offset so that the number decreases and it may go up the column (first 
        last-offset) and left (latter). */

       //shift right to bottom
       matrix[last][last-offset]=matrix[i][last];
        /*I understand that it i so that in the next iteration, it moves down 
        the column*/        



       //rightmost top corner
        matrix[i][last]=top;
       }
   }

}

【问题讨论】:

    标签: algorithm matrix multidimensional-array rotation


    【解决方案1】:

    如果你画一张图,这样的算法会更容易理解,所以我在 Paint 中制作了一张快速图片来演示 5x5 矩阵:D

    外部for(int layer=0; layer &lt; n/2; ++layer) 循环从外到内遍历层。外层(第 0 层)由彩色元素描绘。每一层实际上是一个需要旋转的正方形元素。对于 n = 5,layer 将采用从 0 到 1 的值,因为有 2 层,因为我们可以忽略不受旋转影响的中心元素/层。 first 和 last 指的是图层元素的第一行和最后一行/列;例如第 0 层的元素从行/列 first = 0 到 last = 4,第 1 层的元素从行/列 1 到 3。

    然后对于每个层/正方形,内部for(int i=first; i&lt;last;++i) 循环通过在每次迭代中旋转 4 个元素来旋转它。 Offset 表示我们在正方形边上的距离。对于下面的 5x5,我们首先旋转红色元素(偏移 = 0),然后旋转黄色(偏移 = 1),然后旋转绿色和蓝色。箭头 1-5 展示了红色元素的 4 元素旋转,其余部分以相同的方式执行 6+。请注意 4 元素旋转本质上是一个 5 赋值循环交换,第一个赋值暂时搁置一个元素。此分配的 //save the top left of the matrix 注释具有误导性,因为 matrix[first][i] 不一定是矩阵的左上角,甚至不一定是该层。另外,请注意,被旋转元素的行/列索引有时与 offset 成正比,有时与它的倒数成正比,last - offset。

    我们以这种方式沿着外层的两侧移动(由 first=0 和 last=4 描绘),然后移动到内层(first = 1 和 last = 3)并在那里做同样的事情。最终,我们击中了中心,我们就完成了。

    【讨论】:

      【解决方案2】:

      这会触发 WTF。旋转矩阵的最简单方法是通过

      • 首先转置矩阵(将 M[i,j] 与 M[j,i] 交换)
      • 然后将 M[i,j] 与 M[i, nColumns - j] 交换

      当矩阵主要是列时,第二个操作是交换列,因此具有良好的数据局部性属性。如果矩阵主要是行,则先置换行,然后转置。

      【讨论】:

      • 我同意这是一种更简单的方法,但是对于小型矩阵来说效率会不会低很多?转置矩阵将元素移动到正确的行,但错误的列,这需要以后更正。 OP 的算法在第一时间将元素移动到正确的行和列(总共更少的分配)。我在这个比较中忽略了局部性,因为它对于小矩阵来说不是问题。对于大型矩阵,我们可能希望改变 OP 算法中的赋值顺序,并优化该算法中的转置。
      • @Nathan:两种方法执行相同数量的内存加载和内存分配(请记住,交换临时通常是一个寄存器,以及 OP 代码中的top)。这个简单易读,并且可能比不连续处理数据的提议更有效。
      【解决方案3】:

      这是解决这个问题的递归方法:

      // 将二维数组 (mXn) 旋转 90 度

      public void rotateArray(int[][] inputArray) {
          System.out.println("Input Array: ");
          print2D(inputArray);
          rotateArray(inputArray, 0, 0, inputArray.length - 1,
                  inputArray[0].length - 1);
          System.out.println("\n\nOutput Array: ");
          print2D(inputArray);
      
      }
      
      public void rotateArray(int[][] inputArray, int currentRow,
              int currentColumn, int lastRow, int lastColumn) {
      
          // condition to come out of recursion.
          // if all rows are covered or all columns are covered (all layers
          // covered)
          if (currentRow >= lastRow || currentColumn >= lastColumn)
              return;
          // rotating the corner elements first
          int top = inputArray[currentRow][currentColumn];
          inputArray[currentRow][currentColumn] = inputArray[lastRow][currentColumn];
          inputArray[lastRow][currentColumn] = inputArray[lastRow][lastColumn];
          inputArray[lastRow][lastColumn] = inputArray[currentRow][lastColumn];
          inputArray[currentRow][lastColumn] = top;
      
          // clockwise rotation of remaining elements in the current layer
          for (int i = currentColumn + 1; i < lastColumn; i++) {
              int temp = inputArray[currentRow][i];
              inputArray[currentRow][i] = inputArray[lastRow - i][currentColumn];
              inputArray[lastRow - i][currentColumn] = inputArray[lastRow][lastColumn
                      - i];
              inputArray[lastRow][lastColumn - i] = inputArray[currentRow + i][lastColumn];
              inputArray[currentRow + i][lastColumn] = temp;
          }
      
          // call recursion on remaining layers
          rotateArray(inputArray, ++currentRow, ++currentColumn, --lastRow,
                  --lastColumn);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-27
        • 1970-01-01
        • 2015-07-17
        • 2019-03-06
        • 2022-01-07
        • 2017-10-07
        • 2011-03-22
        • 1970-01-01
        相关资源
        最近更新 更多