用于插入二进制搜索树的两种类似算法

时间:2014-05-22 10:46:26

标签: java algorithm binary-search-tree

我上次询问similar question关于下面第二个算法的问题并被引用到Is Java “pass-by-reference” or “pass-by-value”?线程。

当你将一个变量传递给一个方法时,我会得到它,Java会创建一个它的阴影副本,这样你就无法修改原始变量,但这正是让我感到困惑的原因。

下面是我最初在根节点中传递的两个有点类似的算法 - 第一个可以工作,但第二个没有。

第一

public void insert(int element) {
    Node temp = new Node(element);

    if(root == null) {
        root = temp;
        root.parent = null;
        size++;
    } else {
        insert(root, temp); 
        size++;
    }
}

private void insert(Node current, Node temp) {
    if(temp.element < current.element) {
        if(current.leftChild == null) {
            current.leftChild = temp;
        } else {
            insert(current.leftChild, temp);
        }
    } 
    else if(temp.element >= current.element) {
        if(current.rightChild == null) {
            current.rightChild = temp;
        } else {
            insert(current.rightChild, temp);
        }
    }
}

输出继电器:

enter image description here

秒(不起作用)

public void insert(int data) {
    Node temp = new Node(data);

    if(root == null) {
        root = temp;
        size++;
    } else {
        insert(root, temp);
        size++;
    }
}

private void insert(Node current, Node temp) {
    if(current == null)
        current = temp;
    else if(temp.element < current.element)
        insert(current.leftChild, temp);
    else if(temp.element >= current.element)
        insert(current.rightChild, temp);
}

输出:

enter image description here

我自己写了第一个,并从Wikipedia获得了第二个。为什么第一个工作而不是第二个?

2 个答案:

答案 0 :(得分:1)

它不起作用,因为您没有在树中连接元素'temp'。 假设您已到达必须在树中添加临时值的位置。假设 在某个阶段你有最新的和

  

current.leftchild = null ,你必须在这里添加temp。在第二种方法中做的是   你必须 current.leftchild 并为其分配 temp ,但你实际上没有指出   指向temp.Thus temp 的指针将无法访问,也不会形成树。   那就是你必须保留返回类型Node来解决问题。

答案 1 :(得分:1)

让我们来看看哪些参考文献。 (Java引用,不要与C ++混淆 - 引用)

假设我们有一些带地址的内存,在这种情况下,数据是一些字符串对象

[ address ][ data ]
[       0 ][  abc ]
[       1 ][   de ]
[       2 ][    y ]
[       3 ][  foo ]
[       4 ][ baar ]

如果我们有一个引用,那么这个引用只是一个地址,而不是数据本身!

int i = 15; // this is a primitive type, the variable i holds the data directly
            // 15 in this case

Number x = new StringObject(foo); // this is a reference, the reference only 
                                  // contains the address.
                                  // so x is actually '3'

现在,如果我们调用方法会发生什么?传递给方法的每个值都将被复制。

void call(int x) {
    x = 4;
}

int i = 15;
call(i);
System.out.println(i);

此输出将为15.因为i的值被复制到调用方法。并且该方法仅更改副本,但不更改原始i。

参考资料也是如此:

void call(StringObject x) {
    x = new StringObject("baz"); // this creates a new address in x!
}

StringObject i = new StringObject("foo"); // remember, i is only an address!
                                          // the address is '3'
                                          // the actual value can be looked up
                                          // in our memory table above
                                          // '3' -> 'foo'

call(i);
System.out.println(i);

此处的输出为foo。与原语一样,i将被复制。但不要担心,只会复制地址。结果是,调用方法适用于i的副本3。但原始i的值不会更改。

那么,你问题的联系是什么?请参阅此方法:

private void insert(Node current, Node temp) {
    if(current == null)
        current = temp;
    else if(temp.element < current.element)
        insert(current.leftChild, temp);
    else if(temp.element >= current.element)
        insert(current.rightChild, temp);
}

显然,您可以看到,您的代码在current引用的副本上运行!您正在更改将在方法之后丢弃的副本。基本上第二个代码解决问题的方法是使用第一个代码片段。你可以使用一些包装器对象,比如C ++ - 引用,但是这很复杂并且容易出错。