这两个BST插入操作的实现有什么区别?

时间:2015-12-01 12:04:38

标签: java data-structures binary-search-tree

有代码:

public class BST {
    public Node root;

    private class Node {
        int key;
        String value;
        int N;
        Node left, right;

        public Node(int k, String v, int n) {
            key = k;
            value = v;
            N = n;
        }
    }

    public String get(int key) {
        return get(root, key);
    }

    private String get(Node n, int k) {
        if(n == null) {
            return null;
        }
        if(k == n.key) {
            return n.value;
        } else {
            if(k < n.key) {
                return get(n.left, k);
            } else {
                return get(n.right, k);
            }
        }
    }

    //    This snippet puzzles me
    public void put(int key, String value) {
        root = put(root, key, value);
    }

    private Node put(Node n, int k, String v) {
        if(n == null) {
            return new Node(k, v, 1);
        }
        if(n.key == k) {
            n.value = v;
        } else {
            if(k < n.key) {
                n.left = put(n.left, k, v);
            } else {
                n.right = put(n.right, k, v);
            }
        }
        n.N = size(n.left) + size(n.right);
        return n;
    }
    //    snippet ends


    public static void main(String[] args) {
        BST r = new BST();
        r.put(2, "root");
        r.put(1, "left");
        r.put(3, "right");

        System.out.println(r.get(2));
        System.out.println(r.get(1));
        System.out.println(r.get(3));
    }


}

输出:

root
left
right

一切正常:)

但是,当我像这样更改put方法时:

    public void put(int key, String value) {
        put(root, key, value);
    }

    private void put(Node n, int k, String v) {
        if(n == null) {
            n = new Node(k, v, 1);
        }
        if(n.key == k) {
            n.value = v;
        } else {
            if(k < n.key) {
                put(n.left, k, v);
            } else {
                put(n.right, k, v);
            }
        }
        n.N = size(n.left) + size(n.right);
    }

我得到了输出

null
null
null

显然,新的put方法失败了。但为什么?在我看来,这两种不同的实现方式差别不大。

2 个答案:

答案 0 :(得分:1)

更改作业时

n.left = put(n.left, k, v);

put(n.left, k, v);

(或与n.right相同),并且您还没有节点,您将新节点分配给n变量,但您没有更新链接从递归调用返回的父项到子项。因此,新节点将保持孤立状态,因为您在最后一次递归调用中更改了n的引用,而不是n.left(或右)父级引用。此外,我猜测当参考n的值将在最后一次递归调用结束时被释放,因为没有其他引用指向新创建的节点,这最终将被垃圾收集器消除。

答案 1 :(得分:1)

在Java中,当您阅读Node n时,n是引用的本地副本。分配此本地副本时,它不会更改调用方中的副本。即

private void put(Node n, int k, String v) {
    if(n == null) {
        n = new Node(k, v, 1); // this doesn't change the caller.
    }

如果您没有返回要分配给rootn.leftn.right的节点,那么您正在创建一个节点,但是您没有将其添加到树。

如果您想进一步调查此问题,我建议您逐步调试调试器中的代码,您将能够看到每行代码的作用。