【问题标题】:What changes when implementing lazy deletion into a binary search tree exactly?将延迟删除完全实现到二叉搜索树时会发生什么变化?
【发布时间】:2016-04-14 03:35:34
【问题描述】:

好的,所以我已经研究了好几天了,每次我认为我已经完成了它,我就开始编写代码,并且我到了一个我无法弄清楚到底该怎么做的地步。

这棵树不是递归的,所以我可以真正遵循一切,直到我开始尝试修改它,所以它使用延迟删除而不是真正的删除。 (现在它会清空它删除的节点)

我已经设法弄清楚了:

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

我不知道的:

  1. 我查看了很多资源,有人说您需要做的就是设置 节点的已删除标志为真。这是否意味着我不必 担心设置标志后的链接?
  2. 是一种非常肤浅的适当方法吗?例如,如果标记设置为已删除,即使方法确实找到了某些东西,也不要让方法报告找到了某些东西?
  3. 我应该更改哪些方法以使用延迟删除?只有 delete() 方法?
  4. 如果我只更改删除方法,其他方法是如何获取的?
  5. 搜索方法看起来还行吗?

这是其余的代码,因此您可以看到我在使用什么。我真的很沮丧,因为老实说,我比这个愚蠢的延迟删除实现更好地理解如何完全删除节点。这是他们在书中教的!哈哈

请帮忙... :(


搜索方法

所以这是我的搜索方法:

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!";
}

树类

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

打包 mybinarytreeexample;

公共类 MyBinaryTree> {

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;

【问题讨论】:

  • 我猜你的“延迟删除”实际上意味着添加一个“已删除”的布尔标志并将其标记为真/假。搜索和之前一样,除了找到节点之后,检查这个“deleted”标志,如果是True,返回“NOT FOUND”。如果为 False,则返回节点值。

标签: java algorithm binary-search-tree


【解决方案1】:

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

我查看了很多资源,有人说你需要做的就是设置 节点的已删除标志为真。这是否意味着我不必 担心设置标志后的链接?

是的,如果链接是指 node.left、node.right。删除只是标记为已删除,仅此而已。它没有任何改变,也不应该改变,因为即使 x 或 y 被标记为已删除,x.CompareTo(y) 也必须仍在工作

这是一种非常肤浅的适当方法吗?就像,只是不要 如果标志设置为,让方法报告发现了某些东西 即使方法确实找到了一些东西,也被删除了?

根据这个方法的定义,“某事”是指没有删除标志的节点。对于树的用户来说,任何带有已删除标志的东西都是“无”的。

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

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

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

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

可能还有其他人。

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

【讨论】:

  • 对不起,我花了这么长时间才得到这个答案,我最终弄明白了,完全忘记了我已经发布了这个。但是感谢您的回答,它的格式很好。我喜欢人们以你的方式回答问题。
猜你喜欢
  • 2013-12-08
  • 1970-01-01
  • 2015-03-04
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-23
相关资源
最近更新 更多