将延迟删除完全实现到二叉搜索树时会发生什么变化?

时间:2016-04-14 03:35:35

标签: java algorithm binary-search-tree

好的,所以我一直在研究这几天,每次我想我已经把它弄下来我开始编写代码而我到达了一个我无法弄清楚究竟是什么的点要做。

树不是递归的,所以我可以真正地遵循所有内容,直到我开始尝试修改它,因此它使用延迟删除而不是真正的删除。 (现在它将删除的节点归零)

我设法弄清楚:

  • 我在节点类中添加了一个标志,将它们设置为已删除
  • 我已经实现了一个有效的搜索方法,它甚至可以注册我的节点是否被删除(懒惰)
  • 我知道树类的其余部分应该将标记为已删除的节点视为不存在。

我不知道的事情:

  1. 我看过很多资源,有些人说你需要做的就是设置 节点的已删除标志为true。这是否意味着我不必 在设置旗帜后担心链接?
  2. 这是非常肤浅的合适方式吗?就像在,如果标志设置为删除,即使方法确实找到了什么,也不要让方法报告发现了什么?
  3. 我应该使用哪种方法更改为使用延迟删除?只有delete()方法?
  4. 如果我只更改删除方法,其他方法如何选择?
  5. 搜索方法看起来不错吗?
  6. 这是代码的其余部分,以便您可以看到我正在使用的内容。我真的很沮丧,因为我老老实实地理解如何完全删除节点比这个愚蠢的延迟删除实现更好。这是他们在书中教的内容!洛尔

    请帮助...... :(

    搜索方法

    所以这是我的搜索方法:

    public String search(E data){
        Node<E> current = root;
        String result = "";
    
        while(current != null){
            if(data.compareTo(current.e) < 0){
                current = current.left;
            }
            else if (data.compareTo(current.e) > 0){
                current = current.right;
            }
            else{
                if (current.isDeleted == false){
                    return result += "Found node with matching data that is not deleted!";
                }
                else{
                    return result += "Found deleted data, not usable, continuing search\n";
                }
            }
        }
    
        return result += "Did not find non-deleted matching node!";
    }
    

    树类

    树代码(真正的删除方法在最后被注释掉,所以我可以用延迟删除替换它):

    package mybinarytreeexample;

    公共类MyBinaryTree&gt; {

    private Node<E> root = null;
    
    public class Node<E> {
        public boolean isDeleted = false;
        public E e = null;
        public Node<E> left = null;
        public Node<E> right = null;
    }
    
    public boolean insert(E e) {
        // if empty tree, insert a new node as the root node
        // and assign the elementy to it
        if (root == null) {
            root = new Node();
            root.e = e;
            return true;
        }
    
        // otherwise, binary search until a null child pointer 
        // is found
        Node<E> parent = null;
        Node<E> child = root;
    
        while (child != null) {
            if (e.compareTo(child.e) < 0) {
                parent = child;
                child = child.left;
            } else if (e.compareTo(child.e) > 0) {
                parent = child;
                child = child.right;
            } else {
                if(child.isDeleted){
                    child.isDeleted = false;
                    return true;
                }
                return false;
            }
        }
    
        // if e < parent.e create a new node, link it to 
        // the binary tree and assign the element to it
        if (e.compareTo(parent.e) < 0) {
            parent.left = new Node();
            parent.left.e = e;
        } else {
            parent.right = new Node();
            parent.right.e = e;
        }
        return true;
    }
    
    public void inorder() {
        System.out.print("inorder:   ");
        inorder(root);
        System.out.println();
    }
    private void inorder(Node<E> current) {
        if (current != null) {
            inorder(current.left);
            System.out.printf("%3s", current.e);
            inorder(current.right);
        }
    }
    
    public void preorder() {
        System.out.print("preorder:  ");
        preorder(root);
        System.out.println();
    }
    private void preorder(Node<E> current) {
        if (current != null) {
            System.out.printf("%3s", current.e);
            preorder(current.left);
            preorder(current.right);
        }
    }
    
    public void postorder() {
        System.out.print("postorder: ");
        postorder(root);
        System.out.println();
    }
    private void postorder(Node<E> current) {
        if (current != null) {
            postorder(current.left);
            postorder(current.right);
            System.out.printf("%3s", current.e);
        }
    }
    
    public String search(E data){
        Node<E> current = root;
        String result = "";
    
        while(current != null){
            if(data.compareTo(current.e) < 0){
                current = current.left;
            }
            else if (data.compareTo(current.e) > 0){
                current = current.right;
            }
            else{
                if (current.isDeleted == false){
                    return result += "Found node with matching data that is not deleted!";
                }
                else{
                    return result += "Found deleted data, not usable, continuing search\n";
                }
            }
        }
    
        return result += "Did not find non-deleted matching node!";
    }
    
    public boolean delete(E e) {
    
    
    }
    
    
    // an iterator allows elements to be modified, but can mess with
    // the order if element not written with immutable key; it is better
    // to use delete to remove and delete/insert to remove or replace a
    // node
    public java.util.Iterator<E> iterator() {
        return new PreorderIterator();
    }
    
    private class PreorderIterator implements java.util.Iterator<E> {
    
        private java.util.LinkedList<E> ll = new java.util.LinkedList();
        private java.util.Iterator<E> pit= null;
    
        // create a LinkedList object that uses a linked list of nodes that
        // contain references to the elements of the nodes of the binary tree 
        // in preorder
        public PreorderIterator() {
            buildListInPreorder(root);
            pit = ll.iterator();
        }
    
        private void buildListInPreorder(Node<E> current) {
            if (current != null) {
                ll.add(current.e);
                buildListInPreorder(current.left);
                buildListInPreorder(current.right);
            }
        }
    
        // check to see if their is another node in the LinkedList
        @Override
        public boolean hasNext() {
            return pit.hasNext();
        }
    
        // reference the next node in the LinkedList and return a 
        // reference to the element in the node of the binary tree
        @Override
        public E next() {
            return pit.next();
        }
    
        @Override
        public void remove() { 
            throw new UnsupportedOperationException("NO!");
        }
    }
    }
    
    
    // binary search until found or not in list
    //        boolean found = false;
    //        Node<E> parent = null;
    //        Node<E> child = root;
    //        
    //        while (child != null) {
    //            if (e.compareTo(child.e) < 0) {
    //                parent = child;
    //                child = child.left;
    //            } else if (e.compareTo(child.e) > 0) {
    //                parent = child;
    //                child = child.right;
    //            } else {
    //                found = true;
    //                break;
    //            }
    //        }        
    //        
    //        
    //        if (found) {
    //            // if root only is the only node, set root to null
    //            if (child == root && root.left == null && root.right == null)
    //                root = null;
    //            // if leaf, remove
    //            else if (child.left == null && child.right == null) {
    //                if (parent.left == child)
    //                    parent.left = null;
    //                else 
    //                    parent.right = null;
    //            } else
    //                // if the found node is not a leaf
    //                // and the found node only has a right child, 
    //                // connect the parent of the found node (the one 
    //                // to be deleted) to the right child of the 
    //                // found node 
    //                if (child.left == null) {
    //                    if (parent.left == child)
    //                        parent.left = child.right;
    //                    else 
    //                        parent.right = child.right;
    //            } else {
    //                // if the found node has a left child,
    //                // the node in the left subtree with the largest element 
    //                // (i. e. the right most node in the left subtree) 
    //                // takes the place of the node to be deleted
    //                Node<E> parentLargest = child;
    //                Node<E> largest = child.left;
    //                while (largest.right != null) {
    //                    parentLargest = largest;
    //                    largest = largest.right;
    //                }
    //                
    //                // replace the lement in the found node with the element in
    //                // the right most node of the left subtree
    //                child.e = largest.e;
    //                
    //                // if the parent of the node of the largest element in the 
    //                // left subtree is the found node, set the left pointer of the
    //                // found node to point to left child of its left child
    //                if (parentLargest == child)
    //                    child.left = largest.left;
    //                else 
    //                    // otherwise, set the right child pointer of the parent of 
    //                    // largest element in the left subtreeto point to the left
    //                    // subtree of the node of the largest element in the left 
    //                    // subtree
    //                    parentLargest.right = largest.left;
    //            }
    //            
    //        } // end if found
    //        
    //        return found;
    

1 个答案:

答案 0 :(得分:1)

您的树只会根据所使用的真实空间而增长,并且永不缩小。如果您选择列表作为实现树的数据结构,而不是通常的构造Node E {V value; E right; E; left},这将非常有用。我稍后会再回来。

  

我看过许多资源,有些人说你需要做的就是设置   节点的已删除标志为true。这是否意味着我不必   在设置旗帜后担心链接?

是的,如果通过链接你的意思是node.left,node.right。删除只需将其标记为已删除即可。它不会改变任何其他内容,它不应该,因为即使x或y标记为已删除,x.CompareTo(y)必须仍然有效

  

这样做是非常肤浅的合适方式吗?就像在,不要   如果标志设置为,则让方法报告找到了某些内容   即使方法确实找到了什么,也删除了?

这种方法的定义&#34;东西&#34;表示没有删除标志的节点。删除标志的任何内容都是&#34;没有&#34;对于树的用户。

  

我应该更改哪些方法来使用延迟删除?只有删除()   方法

当然不是。您已经自己更改了搜索方法。我们来看isEmpty()。您应该保留已删除节点和总节点之一的计数器。如果它们相等,则树是空的。否则树不是。

您的算法中存在一个小错误。当您插入并发现已登陆已删除的节点时,您只需取消标记该节点。您还必须设置节点的值。毕竟compareTo并不确保所有字段都严格相等,只是对象是等价的。

 if(child.isDeleted){
      child.isDeleted = false;
      child.e = e; <---- missing
      return true;
 }

可能还有其他人。

旁注: 如前所述,此方法有用的一个实例是由列表支持的树(让我们说数组列表)。使用此方法,位置i处元素的子元素位于2*i+12*i+2位置。通常,当您删除带有子节点的节点p时,将该节点替换为右子树的最左侧节点q(或左子树中最右侧的节点)。在这里,您可以将p标记为已删除,并交换已删除节点的值和最左侧。 您的阵列在内存中保持不变