【问题标题】:Why is the value of 'count' not kept across different recursions? [duplicate]为什么'count'的值没有在不同的递归中保持? [复制]
【发布时间】:2016-05-11 13:06:34
【问题描述】:

这是用于计算数组中反转的 Java 代码。

private void findInversions(int begin, int end, Integer count) {
    System.out.println("begin: " + begin + ", end: " + end + ", and count is " + count);
    if (end - begin < 1)
        return;
    int middle = (begin + end) / 2;
    findInversions(begin, middle, count);
    System.out.println("begin: " + begin + ", end: " + end + ", here count is " + count);
    findInversions(middle + 1, end, count);
    mergeAndCount(begin, middle, end, count);
    System.out.println("begin: " + begin + ", end: " + end + ", count now is: " + count);
}



private void mergeAndCount(int begin, int middle, int end, Integer count) {

    int[] result = new int[end - begin + 1];
    int aptr = begin;
    int bptr = middle + 1;
    for (int i = 0; i < result.length; i++) {
        if (aptr <= middle && bptr <= end) {
            if (numbers[aptr] < numbers[bptr]) {
                result[i] = numbers[aptr];
                aptr++;
            }
            else { // numbers[aptr] > numbers[bptr]
                // (a[aptr], b[bptr]) is an inversion here
                count++;
                System.out.println("Found: (" + numbers[aptr] + "," + numbers[bptr] + ") " + count);
                result[i] = numbers[bptr];
                bptr++;
            }
        }
        else if (aptr > middle) {
            result[i] = numbers[bptr];
            bptr++;
        }
        else if (bptr > end) {
            result[i] = numbers[aptr];
            aptr++;
        }

    }

    for (int i = 0; i < result.length; i++) {
        numbers[begin + i] = result[i];
    }

}

反转打印得很好,但count 永远不会正确,因为在递归调用返回后它会丢失其值。我已经调试了几次,我所看到的只是当递归结束时count 再次变为 0,但我找不到原因。谁能解释一下?

【问题讨论】:

  • 您为什么希望它被保留? Java 对所有内容都使用按值传递,包括对 Integer 对象的引用。注意count++会创建一个新的Integer对象;所有 Java 包装器类型都是不可变的。如果您愿意,可以使用 AtomicInteger 作为可变包装类型...
  • Integer类在java中不是不可变的吗?
  • @EmanuelOster 是的。但即使不是这样,它也不会起作用,因为我的回答中有描述。

标签: java recursion pass-by-reference


【解决方案1】:

Integer 是一个不可变的类。在执行count++ 时,该值会自动拆箱为int,此int 会递增并将结果分配给count。但是您不会修改填充到方法中的实例。你可以e。 G。使用AtomicInteger 实例,然后使用incrementAndGet()getAndIncrement() 方法。

【讨论】:

  • 谢谢,但即使 Integer 是可变的,为什么它也不起作用?我的意思是,值可以改变对吗?
  • 可以,但不会。正如您在我的回答中看到的那样,先拆箱,然后用分配的新值装箱,因此修改了新对象而不是同一个对象。如果Integer 是可变的并且它有一个方法increment()并且你会使用它而不是++(Java 中没有运算符重载),那么它会起作用,就像你使用AtomicInteger一样,因为所有这些都是正确的。它增加了一些同步开销,因此如果性能很重要,您可以创建一个自己的持有者类,其中包含一个 int 和一个要使用的递增方法。
【解决方案2】:

您的mergeAndCount() 方法应该返回它获得的计数。调用这些方法的方法应该使用返回值。而且我将其保留为整数,但没有必要;你可以使用原语int

private Integer findInversions(int begin, int end, Integer count) {
    // ... do all your stuff here but change recursive calls:
    count += findInversions(begin, end, count);
    count += mergeAndCount(begin, middle, end, count0;
    // and return what you find
    return count;
}

private Integer mergeAndCount(int begin, int middle, int end, Integer count) {
    // ... do all your stuff here
    return count;
}

由于numbers 显然是您的计数类中的一个字段,您的另一种选择是将count 保留为类中的一个字段。这将与您所寻求的效果相同。

【讨论】:

  • 感谢您的宝贵时间。我想继续传递count 作为递归练习的参数(并且思考!)。我一直认为我的代码中存在错误,所以我坚持保持这种方式并找出原因。你可以说我不够“有信誉”来支持你的答案。
猜你喜欢
  • 2023-03-23
  • 2021-01-12
  • 2020-03-20
  • 2021-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-13
相关资源
最近更新 更多