繁体   English   中英

递归二叉搜索树删除

[英]Recursive Binary Search Tree Deletion

注意:如果我的错误所在,我已经包括了插入代码。

我在删除二进制搜索树中的节点时遇到问题。 我在eclipse中运行了它,似乎重新分配了节点的“指针”,但是一旦退出递归方法,它就会回到节点的状态。

我可能会误解java如何在方法之间传递树节点。

public abstract class BinaryTree<E> implements Iterable<E> {

    protected class Node<T> {

        protected Node(T data) {
            this.data = data;
        }

        protected T data;
        protected Node<T> left;
        protected Node<T> right;
    }

    public abstract void insert(E data);
    public abstract void remove(E data);
    public abstract boolean search(E data);

    protected Node<E> root;
}

import java.util.Iterator;

public class BinarySearchTree<E extends Comparable<? super E>> extends BinaryTree<E> {

    private Node<E> findIOP(Node<E> curr) {

        curr = curr.left;

        while (curr.right != null) {
            curr = curr.right;
        }

        return curr;
    }

public Iterator<E> iterator() {

    return null;
}

public static void remove(E data) {

    if (root != null){

         if (data.compareTo(root.data) == 0) {

            if (root.left == null || root.right == null) {

                root = root.left != null ? root.left : root.right;


            } else {

                Node<E> iop = findIOP(root);
                E temp = root.data;
                root.data = iop.data;
                iop.data = temp;

                if (root.left == iop) {

                    root.left = root.left.left;

                } else {

                    Node<E> curr = root.left;

                    while (curr.right != iop) {
                        curr = curr.right;
                    }
                    curr.right = curr.right.left;
                }
            }

        } else {

             if (data.compareTo(root.data) < 0) {

                remove(root.left ,data);

             } else {

                remove(root.right ,data);

             }
        }

    }
}

private void remove (Node<E> node, E data){

     if (data.compareTo(node.data) == 0) {

        if (node.left == null || node.right == null) {


            if (node.left != null) {
                                    // Problem is either here
                node = node.left;

            } else {
                                    // or here
                node = node.right;
            }


        } else {

            Node<E> iop = findIOP(node);
            E temp = node.data;
            node.data = iop.data;
            iop.data = temp;

            if (node.left == iop) {

                node.left = node.left.left;

            } else {

                Node<E> curr = node.left;

                while (curr.right != iop) {
                    curr = curr.right;
                }
                curr.right = curr.right.left;
            }
        }
    } else {

         if (data.compareTo(node.data) < 0) {

            remove(node.left ,data);

         } else {

            remove(node.right ,data);

         }
    }

}

}

当我插入时:

tree.insert(10);
tree.insert(15);
tree.insert(6);
tree.insert(8);
tree.insert(9);

接着

tree.remove(8);

System.out.println(tree.root.left.right.data);

仍然是8而不是9

从root处进行删除操作,如果从root.left和root.right中删除,则会正确分配指针。

任何建议,将不胜感激。

编辑:我似乎已经缩小了问题。 我实现了一个迭代版本,其中使root = curr并更改curr.left.right = curr.left.right.right。 我注意到此更改反映了我的根节点,而当我将node = root.left.right传递给递归函数时,将节点更改为node.right并不反映根目录中的更改。 为什么是这样?

缩小一些。 为什么node.left = node.left.left会对我的树进行更改,而node = node.left却无济于事。

我通过递归重新分配父节点而不是递归重新分配子节点来解决此问题。 这就是由此产生的私人和公共职能。

public void remove(E data) {

    Node<E> curr;

    if (root != null) {
        if (data.compareTo(root.data) == 0) {
            if (root.left == null || root.right == null) {
                root = root.left != null ? root.left : root.right;
            }
            else {
                Node<E> iop = findIOP(root);
                E temp = root.data;
                root.data = iop.data;
                iop.data = temp;
                if (root.left == iop) {
                    root.left = root.left.left;
                }
                else {
                    curr = root.left;
                    while (curr.right != iop) {
                        curr = curr.right;
                    }
                    curr.right = curr.right.left;
                }
            }
        } else if (data.compareTo(root.data) < 0) {
            root.left = remove(data, root.left);
        } else {
            root.right = remove(data, root.right);
        }
    }
}

private Node<E> remove(E data, Node<E> node){

    Node<E> curr;

    if (node != null){
        if (data.compareTo(node.data) == 0) {
            if (node.left == null || node.right == null) {
                node = node.left != null ? node.left : node.right;
                return node;
            } else {

                Node<E> iop = findIOP(node);
                E temp = node.data;
                node.data = iop.data;
                iop.data = temp;
                if (node.left == iop) {
                    node.left = node.left.left;
                    return node;
                } else {
                    curr = node.left;
                    while (curr.right != iop) {
                        curr = curr.right;
                    }
                    curr.right = curr.right.left;
                    return node;
                }
            }
        } else {
            if (data.compareTo(node.data) < 0) {
                node.left = remove(data, node.left);
                if (node.left != null){
                    return node.left;
                }
            } else {
                node.right = remove(data, node.right);
                if (node.right != null){
                    return node.right;
                }
            }
            // if node.left/right not null
            return node;
        }
    }
    // if node = null;
    return node;
}

当您说“我可能会误解java如何在方法之间传递树节点”时,您确实是对的。 考虑:

public class Ref {
    public static void main(String args[]) {
        Integer i = new Integer(4);
        passByRef(i);
        System.out.println(i);    // Prints 4.
    }

    static void passByRef(Integer j) {
        j = new Integer(5);
    }
}

尽管“通过引用传递了i ”,但引用i 本身不会被方法更改,仅j引用的东西。 换句话说,用引用i的副本初始化j ,即j最初引用与i相同的对象(但关键不是i )。 分配j引用其他内容对i引用的内容没有影响。

为了实现搜索中想要的功能,建议您将新引用返回给调用方。 例如,类似于以下更改的内容:

public class Ref {
    public static void main(String args[]) {
        Integer i = new Integer(4);
        i = passByRef(i);
        System.out.println(i);    // Prints 5.
    }

    static Integer passByRef(Integer j) {
        j = new Integer(5);
        return j;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM