【问题标题】:Rotate a 2D array in-place without using a new array - best C++ solution?在不使用新数组的情况下就地旋转二维数组 - 最佳 C++ 解决方案?
【发布时间】:2023-03-23 14:37:01
【问题描述】:

我的一个学生问我这种关于 C++ 数组的作业。这对我来说似乎很有趣,因此,虽然我已经解决了这个问题,但我想与您分享我的解决方案并了解其他变体和意见。问题如下:

问题 给定一个二维动态二次矩阵(数组)A(nxn)。要求将数组逆时针旋转 90 度,即旋转后 A[1,1] 字段应包含 A[1,n] 的值,A[1,n] 字段应包含A[n,n]。 并且还要求在解决此问题时不要使用任何其他数组。

我的解决方案 我已告诉学生执行以下操作(将示意性地表示步骤):
我建议定义一个类,该类作为其成员,将具有 2D 数组。并定义一个操作,当用户请求 A[i,j] 元素时,该操作将返回对 A[j,n+1-i] 元素的引用。简而言之,我建议为数组创建一个包装器,并通过包装器按数组操作。

【问题讨论】:

  • 您的解决方案实际上并不能解决问题。您只是为每个查询返回正确的元素,但实际上并没有像问题要求的那样旋转它。为一个有趣的问题 +1。
  • @IVlad:实际上,解决问题只是一个观点。您可以非常确定 matlab 之类的程序是如何实现矩阵转置的,只使用状态和适当的 getter,没有真正的转换。当然,我怀疑我的老师会在考试中接受这个答案:D。
  • 注意!!!所有这些解决方案都使用一个新数组!解决方案应该是不使用新数组。
  • @nikhil 不用可怜! :) 我已经告诉他们正确的解决方案,当然!您可能会同情学生,他们的老师提出了解决方法并通过了该问题,而没有返回更好的解决方案;)
  • 我很感激您确实在寻找更好的解决方案,我也无意造成任何人身伤害。将删除我的评论。对此感到抱歉。

标签: c++ arrays algorithm


【解决方案1】:

维基百科有一篇关于in-place matrix transposition的文章。

考虑:

a b c
e f g
x y z

transpose:
a e x
b f y
c g z

rotated 90 deg CCW:
c g z
b f y
a e x

因此,在您完成转置后,将行反转,您可以轻松地就地完成。

【讨论】:

  • 等等,这就是我写的!但由于这更清楚,我将删除我的。和 +1 :-)
  • @Moron:我自己也经常遇到问题,我猜我很慢:D
  • @Matthieu: :-) 我的猜测是 stackoverflow 的实现方式(缓存和所有)。因此,即使我在此之前发布了 2-3 分钟,但其他人可能看不到它。无论如何,我有一个非常简洁的答案,而且这个答案更好地解释了该方法为何有效。
【解决方案2】:

您可以使用“四向交换”和带有一些旋转魔法的嵌套循环(在纸上制定):

template <typename T>
void swap(T& a, T& b, T& c, T& d)
{
    T x(a);
    a = b;
    b = c;
    c = d;
    d = x;
}

template <typename T, size_t dim>
void rotate(T (&matrix)[dim][dim])
{
    const size_t d = dim-1;
    for (size_t y = 0; y < dim/2; ++y)
    {
        for (size_t x = y; x < d-y; ++x)
        {
            swap(matrix[y  ][x  ],
                 matrix[x  ][d-y],
                 matrix[d-y][d-x],
                 matrix[d-x][y  ]);
        }
    }
}

测试程序:

template <typename T, size_t dim>
void print(T (&matrix)[dim][dim])
{
    for (size_t y = 0; y < dim; ++y)
    {
        for (size_t x = 0; x < dim; ++x)
        {
            std::cout << matrix[y][x] << ' ';
        }
        std::cout << '\n';
    }
}

int main()
{
    int matrix[4][4] = {{1, 2, 3, 4},
                        {5, 6, 7, 8},
                        {9, 10, 11, 12},
                        {13, 14, 15, 16}};
    rotate(matrix);
    print(matrix);
}

输出:

4 8 12 16
3 7 11 15
2 6 10 14
1 5 9 13

现在您只需将其从模板形式转换为动态形式;)

【讨论】:

  • 递归算法可以更加优雅简洁。
【解决方案3】:

嗯,那不是 C++,而是 Java。对此很抱歉,但这是一个简单数组中的递归算法,支持 Matrix

public void rotateInPlaceRecursive() {
    if( rowCount != colCount ) {
        throw new IllegalStateException("Matrix must be square");
    }
    doRotateInPlaceRecursive(0);
}

public void doRotateInPlaceRecursive(int shrink) {
    if( shrink == rowCount/2 ) {
        return;
    }
    for (int col = shrink; col < colCount-shrink-1; col++) {
        int row = shrink;
        int top     = tab[row][col];
        int left    = tab[rowCount-col-1][row];
        int bottom  = tab[rowCount-row-1][rowCount-col-1];
        int right   = tab[col][rowCount-row-1];

        tab[row][col] = right;
        tab[rowCount-col-1][row] = top;
        tab[rowCount-row-1][rowCount-col-1] = left;
        tab[col][rowCount-row-1] = bottom;

    }
    doRotateInPlaceRecursive(shrink+1);
}

---- 测试

@Test
public void testRotateInPlaceRecursive() {
    // given
    int N = 5;
    Matrix matrix = new Matrix(N, N);

    // when
    int i=0;
    for( int row = 0; row< N; row++ ) {
        for( int col = 0; col< N; col++ ) {
            matrix.set(row,col, i++ );
        }
    }

    // then
    matrix.rotateInPlaceRecursive();
    i = 0;
    for( int row = 0; row< N; row++ ) {
        for( int col = 0; col< N; col++ ) {
            assertEquals(i++,matrix.get(N-col-1,row));
        }
    }
}

【讨论】:

    【解决方案4】:

    下面的例子是用 Java 编写的,可以很容易地被 C++ 采用。在内存中旋转大型矩阵可能会消耗大量资源,尤其是当矩阵的值是复杂对象时。在这种情况下,使用将索引重定向到旋转矩阵元素而不实际旋转的函数重新计算索引可能更有效。

    public class RotateArray {
    
    public static char arr[][] = { { 'a', 'b', 'c','1' }, { 'd', 'e', 'f','2' }, { 'g', 'h', 'i','3' },{ 'j', 'k', 'l','4' } };
    private static int imax = arr.length-1;
    private static int jmax = arr[0].length-1;
    
    public static void printArray() {
    
        for (int i = 0; i <= imax; i++) {
            for (int j = 0; j <= jmax; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.print("\n");
        }
    }
    
    public static void printRotatedArray() {
        for (int i = 0; i <= imax; i++) {
            for (int j = 0; j <= jmax; j++) {
                System.out.print(arr[getRotatedI(i,j)][getRotatedJ(i,j)] + " ");
            }
            System.out.print("\n");
        }
    }   
    
    public static int getRotatedI(int i,int j){     
        int ii = imax-j;
        return ii;
    }
    
    public static int getRotatedJ(int i,int j){
        int jj = i;
        return jj;
    }       
    
    public static void main(String[] args) {
    
        System.out.println("Printing matrix");
        printArray();
        System.out.println("Printing rotated matrix");
        printRotatedArray();
    }
    
    }
    

    输出:

    Printing matrix
    a b c 1 
    d e f 2 
    g h i 3 
    j k l 4 
    
    Printing rotated matrix
    j g d a 
    k h e b 
    l i f c 
    4 3 2 1
    

    【讨论】:

      【解决方案5】:

      O(n^2) 时间和 O(1) 空间算法(没有任何变通方法和手帕的东西!)

      旋转 +90:

      Transpose
      Reverse each row
      

      旋转 -90:

      Transpose
      Reverse each column
      

      旋转+180:

      方法一:旋转两次+90

      方法2:将每一行反转,然后将每一列反转

      旋转 -180:

      方法一:旋转两次-90

      方法2:将每一列反转,然后将每一行反转

      方法 3:相同时反转 +180

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-12
        • 2020-01-05
        • 1970-01-01
        • 2021-12-24
        • 1970-01-01
        • 2021-05-30
        • 2018-05-26
        • 1970-01-01
        相关资源
        最近更新 更多