【问题标题】:Why does the field in my recursive Java method change?为什么我的递归 Java 方法中的字段会发生变化?
【发布时间】:2013-07-25 06:12:49
【问题描述】:

我已经学习 Java 大约一个月了,通过阅读本网站上其他人的问题(和答案)学到了很多东西。我认为以前没有人问过这个问题(但如果有的话,我会很感激一个指针......)

在下面的代码中,几乎所有没有缩进的都是错误检查打印输出,所以代码比看起来要短很多。该代码是我尝试使用递归列出numBalls 球可以放入numBins 箱的所有方式。

主要问题:该方法适用于 numBins numBins 设置为 3,endList 字段(在递归调用中)就有超过 1 个“行”,并且尽快当 j 在正下方的循环中命中 1 时,indexList 字段被更改。例如,main 方法中的calling testList = distributeBallsInBins(1,3,"");(按照它的配置)导致indexList 的第二行从 {0 1 0} 更改为 {0 0 1}(如输出所示),但是当我所做的一切都移到下一个 j(即从 j=0 到 j=1)时,我看不出它是如何/为什么发生变化的

第二个问题:我已将所有出现的Integer[] 替换为int[],似乎没有区别。应该有吗?我想我需要详细了解原始类型和引用类型之间的区别,但我不太了解这里的区别。

提前谢谢你, 迈克

import java.util.*;

public class testRecursion
{
     public static List<Integer[]> distributeBallsInBins(int numBalls, int numBins, String tmpTxt)
    {
        if (numBins==1)
        {
            List<Integer[]> lastList = new ArrayList<Integer[]>();
            lastList.add((new Integer[] {numBalls}));
            return lastList;
        }
        else if (numBalls==0)
        {
            List<Integer[]> lastList = new ArrayList<Integer[]>();
            Integer[] tmpNum = new Integer[numBins];
            for (int k=0; k<numBins; k++)
                tmpNum[k] = 0;
            lastList.add(tmpNum);
            return lastList;
        }
        else
        {
            List<Integer[]> indexList = new ArrayList<Integer[]>();
            for (int i=numBalls; i>=0; i--)
            {
                Integer[] newLine = new Integer[numBins];
                newLine[0] = i;
                List<Integer[]> endList = distributeBallsInBins((numBalls-i), (numBins-1), (tmpTxt + "    "));
                for (int j=0; j<endList.size(); j++)
                {
                    Integer[] newLineEnd = endList.get(j);
                    for (int k=0; k<numBins-1; k++)
                        newLine[k+1] = newLineEnd[k]; 
                    indexList.add(newLine);
                }
            }
        return indexList;
        }
    }

    public static void main(String[] args)
    {
        List<Integer[]> testList = distributeBallsInBins(1,3,"");
    }
}

【问题讨论】:

  • 让我们让世界变得更美好 - 缩进你的代码。
  • 请使用空格而不是制表符来缩进您的代码 - 制表符在 Stack Overflow 中效果不佳。
  • 我做了缩进(除了错误检查之外的所有内容,我没有这样做以便我可以轻松地将其取出),但使用了标签 - 我已经对其进行了编辑以清理它。谢谢提示
  • 我包含了错误打印代码以显示我认为问题出在哪里。我认为这会帮助我解释我所做的事情。根据您的建议,我已将其删除。感谢您的建议。

标签: java recursion pass-by-reference


【解决方案1】:

您的问题是,您总是在修改和插入相同的数组到结果列表中。由于Java 处理每个引用的所有对象,因此您最终会得到一个包含相同数组的列表。

所以在将数组添加到列表之前,您需要 clone 数组:

indexList.add(newLine.clone());

或者每次迭代 j-loop 时创建一个新的 newLine 数组:

for (int j = 0; j < endList.size(); j++) {
    Integer[] newLine = new Integer[numBins];
    newLine[0] = i;
    Integer[] newLineEnd = endList.get(j);
    for (int k = 0; k < numBins - 1; k++)
        newLine[k + 1] = newLineEnd[k];
    indexList.add(newLine);
} // next j

关于对象与基元:更改为 int[] 并没有帮助,因为 array 本身仍然是 Object,因此通过引用传递。

【讨论】:

  • 迈克尔,谢谢。我将不得不阅读克隆,但第二个修复效果很好。我尝试了很多东西,但不是那样(认为我的方式更有效 - 不必每次都设置 newLine[0] 值)。我想我需要更好地理解引用。
  • Michael,关于 int[] 与 Integer[],我没想到会解决问题,只是有点惊讶它没有区别(至少在这个程序中)。再次感谢。
【解决方案2】:

只需替换这一行

indexList.add(newLine);

带线

indexList.add(newLine.clone());

这会工作...... 这将传递新数组而不是传递旧数组的引用.......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-02
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2022-11-10
    • 2015-01-18
    相关资源
    最近更新 更多