受Raymond Chen帖子的启发,假设你有一个4x4二维数组,写一个函数使它旋转90度。Raymond链接到伪代码中的解决方案,但我想看到一些真实的东西。

[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]

更新:Nick的答案是最直接的,但是有没有比n²更好的方法呢?如果矩阵是10000x10000呢?


当前回答

我的c#示例代码的伟大算法发送@dimple:

/* Author: Dudi,
 * http://www.tutorialspoint.com/compile_csharp_online.php?PID=0Bw_CjBb95KQMYm5qU3VjVGNuZFU */

using System.IO;
using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("Rotating this matrix by 90+ degree:");

        int[,] values=new int[3,3]{{1,2,3}, {4,5,6}, {7,8,9}};
        //int[,] values=new int[4,4]{{101,102,103, 104}, {105,106, 107,108}, {109, 110, 111, 112}, {113, 114, 115, 116}};

        print2dArray(ref values);
        transpose2dArray(ref values);
        //print2dArray(ref values);
        reverse2dArray(ref values);
        Console.WriteLine("Output:");
        print2dArray(ref values);
    }

    static void print2dArray(ref int[,] matrix){
        int  nLen = matrix.GetLength(0);
        int  mLen = matrix.GetLength(1);    
        for(int n=0; n<nLen; n++){
            for(int m=0; m<mLen; m++){
                Console.Write(matrix[n,m] +"\t");
            }
            Console.WriteLine();        
        }
        Console.WriteLine();
    }

    static void transpose2dArray(ref int[,] matrix){
        int  nLen = matrix.GetLength(0);
        int  mLen = matrix.GetLength(1);    
        for(int n=0; n<nLen; n++){
            for(int m=0; m<mLen; m++){
                if(n>m){
                    int tmp = matrix[n,m];
                    matrix[n,m] = matrix[m,n];
                    matrix[m,n] = tmp;
                }
            }
        }
    }

    static void reverse2dArray(ref int[,] matrix){
        int  nLen = matrix.GetLength(0);
        int  mLen = matrix.GetLength(1);
        for(int n=0; n<nLen; n++){
            for(int m=0; m<mLen/2; m++){                
                int tmp = matrix[n,m];
                matrix[n,m] = matrix[n, mLen-1-m];
                matrix[n,mLen-1-m] = tmp;
            }
        }
    }
}

/*
Rotating this matrix by 90+ degree:                                                                                                                                             
1       2       3                                                                                                                                                               
4       5       6                                                                                                                                                               
7       8       9                                                                                                                                                               

Output:                                                                                                                                                                         
7       4       1                                                                                                                                                               
8       5       2                                                                                                                                                               
9       6       3  
*/

其他回答

虽然旋转数据可能是必要的(也许是为了更新物理存储的表示),但在数组访问上添加一层间接层(也许是一个接口)会变得更简单,可能更性能:

interface IReadableMatrix
{
    int GetValue(int x, int y);
}

如果你的矩阵已经实现了这个接口,那么它可以通过这样一个装饰器类来旋转:

class RotatedMatrix : IReadableMatrix
{
    private readonly IReadableMatrix _baseMatrix;

    public RotatedMatrix(IReadableMatrix baseMatrix)
    {
        _baseMatrix = baseMatrix;
    }

    int GetValue(int x, int y)
    {
        // transpose x and y dimensions
        return _baseMatrix(y, x);
    }
}

旋转+90/-90/180度,水平/垂直翻转和缩放都可以以这种方式实现。

Performance would need to be measured in your specific scenario. However the O(n^2) operation has now been replaced with an O(1) call. It's a virtual method call which is slower than direct array access, so it depends upon how frequently the rotated array is used after rotation. If it's used once, then this approach would definitely win. If it's rotated then used in a long-running system for days, then in-place rotation might perform better. It also depends whether you can accept the up-front cost.

与所有性能问题一样,测量,测量,测量!

下面是Java语言:

public static void rotateInPlace(int[][] m) {
    for(int layer = 0; layer < m.length/2; layer++){
        int first = layer;
        int last = m.length - 1 - first;
        for(int i = first; i < last; i ++){
            int offset = i - first;
            int top = m[first][i];
            m[first][i] = m[last - offset][first];
            m[last - offset][first] = m[last][last - offset];
            m[last][last - offset] = m[i][last];
            m[i][last] = top;
        }
    }
}

#转置是Ruby的Array类的标准方法,因此:

% irb
irb(main):001:0> m = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2], [3, 4, 5, 6]]
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2], [3, 4, 5, 6]] 
irb(main):002:0> m.reverse.transpose
=> [[3, 9, 5, 1], [4, 0, 6, 2], [5, 1, 7, 3], [6, 2, 8, 4]]

实现是一个用c写的n^2转置函数,你可以在这里看到: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-transpose 通过选择“点击切换源”旁边的“转置”。

我记得比O(n^2)的解更好,但只适用于特殊构造的矩阵(如稀疏矩阵)

当前所有的解决方案都有O(n^2)开销作为临时空间(这不包括那些肮脏的OOP骗子!)这里有一个内存占用为O(1)的解决方案,将矩阵原地右转90度。该死的延展性,这玩意儿跑得很快!

#include <algorithm>
#include <cstddef>

// Rotates an NxN matrix of type T 90 degrees to the right.
template <typename T, size_t N>
void rotate_matrix(T (&matrix)[N][N])
{
    for(size_t i = 0; i < N; ++i)
        for(size_t j = 0; j <= (N-i); ++j)
            std::swap(matrix[i][j], matrix[j][i]);
}

免责声明:我实际上并没有测试这个。让我们玩打虫游戏吧!

下面是Java版本:

public static void rightRotate(int[][] matrix, int n) {
    for (int layer = 0; layer < n / 2; layer++) {
        int first = layer;
        int last = n - 1 - first;
        for (int i = first; i < last; i++) {
           int offset = i - first;
           int temp = matrix[first][i];
           matrix[first][i] = matrix[last-offset][first];
           matrix[last-offset][first] = matrix[last][last-offset];
           matrix[last][last-offset] = matrix[i][last];
           matrix[i][last] = temp;
        }
    }
}

该方法首先旋转最外层,然后按顺序移动到内层。