Java中的M * N矩阵的就地矩阵转置不可能吗?

时间:2016-08-02 17:32:25

标签: java algorithm matrix transpose in-place

是否可以在Java中进行M * N矩阵的就地矩阵转置?我不认为在Java中是可能的,因为在3 * 5矩阵中,3 * 5处的元素理想地与5 * 3处的元素交换,但是这样的位置不存在。比方说,C / C ++,因为内存是连续的,所以是可能的。

此外,还有其他算法,例如发布了here的M * N矩阵,我认为这些算法不适用于Java,但是它与A [i] [j]中交换元素的方式有何不同A [j] [i]因为即使上面链接中的滚动窗口算法也需要辅助存储器?

3 个答案:

答案 0 :(得分:2)

您必须小心使用该术语。严格来说,转置运算符会创建'具有潜在新维度的新矩阵。对于您链接的文章,就地就意味着对初始矩阵和最终矩阵使用相同的内存,这当然可以通过巧妙的表示来实现。

一个简单的解决方案可能是:

public class Matrix {
    private int[][] backingArray;
    private boolean transposed;
    public Matrix(int[][] _backingArray) {
        this.backingArray = _backingArray
    }

    public Matrix(int[] data, rows, columns) {
        backingArray = new int[rows][columns]
        for (int i = 0; i < rows; i++)
            for (int j = 0; j < columns; j++)
                backingArray[i][j] = data[i*columns + j]
    }

    public int getElement(i, j) {
        if (transposed)
            return backingArray[j][i];
        return backingArray[i][j];
    }

    public void transpose() {
        transpose = !transpose;
    }
}

编辑:更正了一些错误的语法

编辑:这样可以根据OP问题读入1-D矩阵(?)

答案 1 :(得分:1)

如果不指定更多的上下文,你的问题并没有太多意义:算法假定数据的线性表示(因为C [++]之类的语言基本上直接访问内存,这是有意义的在那些情况下)。请注意,对于此类表示,您需要在数据外部表示行数和列数。因此,3x4矩阵的数据表示同样可以用于4x3(或2x6等)矩阵,您只需要numberColsnumberRows(伪代码)中的不同值。所以这里的转置算法使用相同的内存分配,但重新排序元素并重新解释行数和列数。

如果您将Java中的(整数)矩阵表示为int[][],那么您不能使用相同的算法,或实际上任何就地转置,因为行和列的数量对于该特定是固定的表示:Java中的数组不可调整大小。该算法不适用,因为数据表示方式不是相同的线性。

但是如果您选择使用单维数组表示矩阵:

public class IntMatrix {

    private final int numColumns ;
    private final int numRows ;

    private final int[] data ;

    public IntMatrix(int numColumns, int numRows, int... data) {
        if (data.length != numColumns*numRows) {
            throw new IllegalArgumentException("...");
        }
        this.numColumns = numColumns ;
        this.numRows = numRows ;
        this.data = new data[numColumns * numRows] ;
        System.arrayCopy(data, 0, this.data, 0, this.data.length);
    }

    public int getElement(int row, int column) {
        return data[column*numRows+row];
    }

    public int getNumRows() {
        return numRows ;
    }

    public int getNumColumns() {
        return numColumns ;
    }
}

那么你当然可以使用完全相同的算法实现就地转置。

然而,你几乎肯定不会:你会做以下事情:

public class IntMatrix {

    // code as before...

    public IntMatrix transpose() {
        return new Transpose(this);
    }

    private static class Transpose extends IntMatrix {
        private IntMatrix original ;
        Transpose(IntMatrix original) { 
            this.original = original ;
        }
        @Override
        public int getElement(int row, int column) {
            return original.getElement(column, row) ;
        }
        @Override
        public IntMatrix transpose() {
            return original ;
        }
        @Override
        public int getNumRows() {
            return original.getNumColumns();
        }
        @Override
        public int getNumColumns() {
            return original.getNumRows();
        }
    }
}

(对于此不可变表示)创建具有O(1)操作和O(1)附加内存的转置。您可以类似地创建可变表示,只需要更多的工作,并且可能更高的成本,具体取决于您想要的确切行为(转置原始可变矩阵的视图等)。

答案 2 :(得分:0)

你是对的,它不可以。在Java中,一旦创建了一个数组,它的长度就固定了。所以,如果M和N不同,你就不能交换它们