【问题标题】:LinkedList retains values even after returning from recursion即使从递归返回,LinkedList 也会保留值
【发布时间】:2012-01-30 06:40:35
【问题描述】:

我有这个函数可以在 BST 中找到从根到叶的所有路径。

public static void paths(Node node, LinkedList<Integer> list) {

    if (node == null) {
        return;
    }
    list.add(node.data);

    if (node.left == null && node.right == null) {
        print(list);
        return;
    } else {
        paths(node.left, list);
        paths(node.right, list);
    }
}

public static void print(LinkedList<Integer> list1) {
    System.out.println("Contents of list: " + list1);
}

我称之为:

LinkedList list = new LinkedList();
paths(bt.root, list);

例如:

07
02
01 05

打印出来:

7 2 1
7 2 1 5 [instead of 7 2 5]

值 1 以某种方式保留在“列表”中,即使它从递归返回后也是如此。

【问题讨论】:

    标签: java recursion linked-list


    【解决方案1】:

    正如其他人所说,这里只使用了一个 LinkedList 对象。 xyz 错误地将其描述为使用按引用传递,但它实际上是按值传递list 的值, 一个引用。 (参数本身的更改,例如为其分配不同的值,对调用者不可见;参数引用的对象内的更改是可见的。)

    了解变量、对象和引用在 Java 中的工作方式真的很重要。当你写(说):

    Node node = new Node();
    

    ...那么node 的值不是Node 对象。这是对Node 对象的引用。赋值和参数传递处理该值(引用)而不是对象。比如:

    Node node1 = new Node();
    Node node2 = node1;
    

    node1node2 现在引用同一个对象 - 不涉及对象复制。

    至于如何解决这个问题,我想到了两个选项:

    • 在每个递归步骤上创建链表的副本,以便更改是独立的
    • 在方法结束时将新添加的值从链表的末尾“弹出”,这样当递归深度n的方法完成时,链表又恢复为n-1元素。

    您可以通过简单地添加调用来做到这一点:

    list.removeLast();
    

    在两个分支中,或者在 finally 块中,或者删除显式的return:

    if (node.left == null && node.right == null) {
        print(list);
        // Note no return statement
    } else {
        paths(node.left, list);
        paths(node.right, list);
    }
    list.removeLast();
    

    【讨论】:

    • 感谢您的回复。它真的帮助我理清了 Java 传递值的概念!
    【解决方案2】:

    我没有看到您从列表中删除任何内容。所以一旦添加它就会一直存在。

    【讨论】:

    • 我递归调用“paths(node.left, list)”。所以当它返回时,我希望它只有 7 和 2。为什么它仍然包含 1?
    • 列表是通过引用传递的,因此一个递归分支中的任何更改都会随处可见
    • 认真的吗?为什么列表是通过引用传递的?因为当我使用数组而不是列表时,它工作正常。所以数组是按值传递的!但是什么是引用传递,什么是值传递呢?我怎么记得。
    • 所有原语都是按值传递的,这意味着,在函数调用中,有一个本地副本,您可以在不更改原始变量的情况下对其进行修改。所有非原始的都通过引用传递。
    • @xyz:不,他们不是。引用是按值传递的,这是另一回事。有必要明确这一点,否则你会让那些真正理解传递引用的人感到困惑。
    【解决方案3】:

    该列表是在递归函数的范围之外创建的,这意味着它与所有递归调用中使用的列表相同。您正在递归地将元素添加到列表中,因此即使在一个递归序列中值是 7 2 51 也会在另一个递归序列中添加到同一个列表中。

    【讨论】:

    • 所以调用LinkedList list = new LinkedList();路径(bt.root,列表);是不正确的!你能建议必要的改变吗?
    猜你喜欢
    • 1970-01-01
    • 2020-03-25
    • 2016-09-27
    • 1970-01-01
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-30
    相关资源
    最近更新 更多