【问题标题】:Matrix Subtraction Confusion (Java)矩阵减法混淆(Java)
【发布时间】:2016-01-15 01:42:02
【问题描述】:

我几乎完成了一个添加、减去和缩放两个矩阵的程序。我为每个测试用例创建了两个测试用例,并在两个矩阵大小不同时添加了错误消息,标准协议。但是,我在第二个减法案例中遇到了问题。这是两个二维数组:

int[][] a = {{1,2},{3,4}};
int[][] b = {{2,3},{5,7}};

这里分别是减法、调用、println:

public static int[][] subtraction(int[][] arr1, int[][] arr2){
        int rows1 = arr1.length;
        int rows2 = arr2.length;
        int columns1 = arr1[0].length;
        int columns2 = arr2[0].length;
        if (rows1 != rows2 || columns1 != columns2){
            System.out.print("Matrices are not the same size, please try again.");
            return null;
        }
        for (int i = 0; i < rows1; i++){
            for (int j = 0; j < columns1; j++){
                arr1[i][j] -= arr2[i][j];
            }
        }
        return arr1;
    }

System.out.println(Arrays.deepToString(subtraction(b, a)));

[[1, 1], [2, 3]]

结账,对吧?那为什么会这样……

System.out.println(Arrays.deepToString(subtraction(a, b)));

...打印这个?

[[1, 2], [3, 4]]

我已经对数组文档和堆栈溢出进行了大量研究,但我从未见过这样的事情。该程序只是打印第一个数组而不是完成计算。我在这里遗漏了什么吗?

感谢您理解我的困境。

【问题讨论】:

  • 当我运行subtraction(a, b) 时,我得到[[-1, -1], [-2, -3]]。你还跑了什么?请记住,您实际上是在修改 arr1。您也将其退回只会使打印更容易。
  • Java 是按值传递的。指向第一个矩阵的引用是不可变的,但它的状态不是。最好创建一个新实例,将差异加载到其中,然后返回新实例。

标签: java arrays matrix


【解决方案1】:

我得到 [[-1, -1], [-2, -3]],这是正确的,减法改变了第一个参数所以运行

System.out.println(Arrays.deepToString(subtraction(b, a)));
System.out.println(Arrays.deepToString(subtraction(a, b)));

[[1, 1], [2, 3]] [[0, 1], [1, 1]]

所以也许你在调用减法(a,b)之前改变了a或?

【讨论】:

  • 我是个白痴。呸!谢谢你的帮助,这让我发疯了。
【解决方案2】:

这就是你想要的:

public class Matrix {

    public static void main(String[] args) {
        int[][] a = {{1,2},{3,4}};
        int[][] b = {{2,3},{5,7}};
        int [][] result = subtraction(b, a);
        System.out.println(toString(result));
        result = subtraction(a, b);
        System.out.println(toString(result));
    }

    private static String toString(int[][] result) {
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        for (int i = 0; i < result[0].length; ++i) {
            builder.append("[");
            for (int j = 0; j < result[i].length; ++j) {
                builder.append(result[i][j]);
                if (j < result[i].length-1) {
                    builder.append(",");
                }
            }
            builder.append("]");
        }
        builder.append("}");
        return builder.toString();
    }

    public static int[][] subtraction(int[][] arr1, int[][] arr2){
        int rows1 = arr1.length;
        int rows2 = arr2.length;
        int columns1 = arr1[0].length;
        int columns2 = arr2[0].length;
        if (rows1 != rows2 || columns1 != columns2){
            System.out.print("Matrices are not the same size, please try again.");
            return null;
        }
        int [][] result = new int[rows1][columns1];
        for (int i = 0; i < rows1; i++){
            for (int j = 0; j < columns1; j++){
                result[i][j] = arr1[i][j] - arr2[i][j];
            }
        }
        return result;
    }
}

【讨论】:

  • 感谢您的意见!我会保存这个以备将来参考。
【解决方案3】:

您看到的问题是您的减法方法正在修改您传递给它的 Array 对象 (array1) 中的值。当您第二次调用该方法时,您现在传递的是数组的修改版本。您可以通过在减法方法中创建 arr1 参数的本地副本来解决此问题,如下所示

public static int[][] subtraction(int[][] arr1, int[][] arr2){
    int rows1 = arr1.length;
    int rows2 = arr2.length;
    int columns1 = arr1[0].length;
    int columns2 = arr2[0].length;
    if (rows1 != rows2 || columns1 != columns2){
        System.out.print("Matrices are not the same size, please try again.");
        return null;
    }
    // Create copies of the input parameter arrays to prevent modifying the origional
    int[][] copy1 = copyOf(arr1);
    for (int i = 0; i < rows1; i++){
        for (int j = 0; j < columns1; j++){
            copy1[i][j] -= arr2[i][j];
        }
    }
    return copy1;
}

public static int[][] copyOf(int[][] origional){
    int[][] copiedArray = new int[origional.length][origional[0].length];
    for(int i=0; i<origional.length; i++){
        for(int j=0; j<origional[i].length; j++){
            int x = origional[i][j];
            copiedArray[i][j] = x;
        }
    }
    return copiedArray;
}

在您的代码中,调用

System.out.println(Arrays.deepToString(subtraction(b, a)));
System.out.println(Arrays.deepToString(subtraction(a, b)));

相当于调用

System.out.println(Arrays.deepToString(subtraction({{2,3},{5,7}}, {{1,2},{3,4}})));
System.out.println(Arrays.deepToString(subtraction({{1,2},{3,4}}, {{1,1},{2,3}}))); // notice that the b array has been modified

当你假设它等同于调用时

System.out.println(Arrays.deepToString(subtraction({{2,3},{5,7}}, {{1,2},{3,4}})));
System.out.println(Arrays.deepToString(subtraction({{1,2},{3,4}}, {{2,3},{5,7}}))); // here the b array has it's original values

要更好地了解为什么会发生这种情况,请参阅以下摘录:

当你将一个对象变量传递给一个方法时,你必须记住你传递的是对象引用,而不是实际的对象本身。请记住,引用变量保存的位代表(对底层 VM)表示访问内存中(堆上)特定对象的方法。更重要的是,您必须记住,您甚至没有传递实际的引用变量,而是引用变量的副本。变量的副本意味着您获得该变量中位的副本,因此当您传递引用变量时,您传递的位的副本表示如何到达特定对象。换句话说,调用者和被调用方法现在都将拥有相同的引用副本;因此,两者都将引用堆上相同的确切(而不是副本)对象。 凯西·塞拉和伯特·贝茨。 “OCA/OCP Java SE 7 程序员 I 和 II 学习指南(考试 1Z0-803 和 1Z0-804)。

【讨论】:

    猜你喜欢
    • 2013-03-25
    • 1970-01-01
    • 2015-12-17
    • 2020-10-01
    • 2012-01-20
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    • 2022-07-07
    相关资源
    最近更新 更多