【问题标题】:In-place matrix rotation就地矩阵旋转
【发布时间】:2011-05-05 20:54:40
【问题描述】:

我发现了一个有趣的问题,要求将 NxN 矩阵原位旋转 90 度。我在 C 中的递归解决方案如下。然而,当我查找其他解决方案时,大多数使用嵌套的for 循环来完成任务(这似乎工作正常)。嵌套循环实现似乎在O(n^2) 时间运行。

见: How do you rotate a two dimensional array?

我相信递归解决方案在O( (n^2-n)/2 ) 中运行,这也是O(n^2)。我的问题有两个。 1) 我上面的复杂性分析对于递归和非递归解决方案是否正确,以及 2) 是否有一些高效或聪明的方法来旋转我还没有找到的矩阵?

TIA。

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


int SIZE = 0;


/**
 * In-place, recursive, clockwise, 90 degree matrix rotation.
 */
static void rotate_in_place( int matrix[][SIZE], int n )
{
    if( n < 2 )
        return;


    int temp1, temp2;

    for( int i = 0; i < (n-1); i++ )
    {
        temp1 = matrix[i][n-1];
        matrix[i][n-1] = matrix[0][i];

        temp2 = matrix[n-1][n-i-1];
        matrix[n-1][n-i-1] = temp1;

        temp1 = matrix[n-i-1][0];
        matrix[n-i-1][0] = temp2;

        matrix[0][i] = temp1;
    }


    matrix = ((int*)matrix) + SIZE + 1;
    n -= 2;
    rotate_in_place( matrix, n );
}


static void print_matrix( int matrix[][SIZE] )
{
    printf( "\n" );
    for( int i = 0; i < SIZE; i++ )
    {
        for( int j = 0; j < SIZE; j++ )
            printf( "%4i ", matrix[i][j] );

        printf( "\n" );
    }
}


int main()
{

    // Create some matrices and rotate them.
    //
        int matrices = 10;

        for( int i = 2; i < matrices; i++ )
        {
            int matrix[i][i];

            int count = 0;
            for( int j = 0; j < i; j++ )
                for( int k = 0; k < i; k++ )
                    matrix[j][k] = ++count;


            printf( "\n\nRotating %ix%i matrix.\n", i, i );

            SIZE = i;

            printf( "\nOriginal matrix.\n" );
            print_matrix( matrix );

            rotate_in_place( matrix, i );

            printf( "\n\nRotated matrix.\n" );
            print_matrix( matrix );
        }


    return EXIT_SUCCESS;
}

【问题讨论】:

  • 您必须将 n*n 个元素移动到新位置,因此很难看出它怎么会小于 O(n^2)。
  • 我几乎不会将此解决方案称为递归。你可以用 goto...

标签: c matrix


【解决方案1】:

原地 C 解决方案如下

void rotateRight(int matrix[][SIZE], int length) {

    int layer = 0;

    for (int layer = 0; layer < length / 2; ++layer) {

        int first = layer;
        int last = length - 1 - layer;

        for (int i = first; i < last; ++i) {

            int topline = matrix[first][i];
            int rightcol = matrix[i][last];
            int bottomline = matrix[last][length - layer - 1 - i];
            int leftcol = matrix[length - layer - 1 - i][first];

            matrix[first][i] = leftcol;
            matrix[i][last] = topline;
            matrix[last][length - layer - 1 - i] = rightcol;
            matrix[length - layer - 1 - i][first] = bottomline;
        }
    }
}

【讨论】:

    【解决方案2】:

    旋转不能在少于 n^2 的操作中完成,因为您需要交换所有元素。然而,通常情况下,由于旋转会严重破坏缓存,我们会避免执行它;)

    【讨论】:

    • 嗯,基本上是同一种问题,转置是绕对角线旋转180度。
    • 是的,除了关于对角线元素的 cmets 不适用于旋转,因此在这种情况下可能会产生误导。
    【解决方案3】:

    您的复杂性分析是正确的,但也很混乱。由于矩阵中的元素数为 n²,因此 O(n²) 是输入大小的有效线性时间,这个数字很重要。

    如果你想在旋转后打印整个矩阵,那么线性时间是你能做的最好的。对于其他操作,最好不要在原地旋转矩阵,而是编写一个 adapter 来更改其索引,因此无需在内存中进行实际旋转即可访问旋转矩阵的元素。

    【讨论】:

      猜你喜欢
      • 2017-05-08
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-08
      • 1970-01-01
      • 2011-05-01
      • 1970-01-01
      相关资源
      最近更新 更多