What changes when implementing lazy deletion into a binary search tree exactly?

半世苍凉 提交于 2020-01-17 05:27:37

问题


Okay so I've been looking into this for days and everytime I think I've gotten it down I start writing code and I get to a point where I just can't figure out what exactly to do.

The tree isn't recursive, so I can follow everything really until I start trying to modify it so it uses lazy deletion instead of real deletion. (Right now it nulls out the node it deletes)

What I have managed to figure out:

  • I added a flag to the node class to set them as deleted
  • I've implemented a search method that works, it even seems to register if my nodes are deleted or not(lazily)
  • I know that the rest of the tree class should treat the nodes that are flagged as deleted such that they are not there.

What I don't know:

  1. I've looked at MANY resources and some say all you need to do is set the node's deleted flag to true. Does this mean that I don't have to worry about the linking after their flag is set?
  2. Is an appropriate way to do this very superficial? As in, just don't let the methods report that something is found if the flag is set to deleted even though the methods do find something?
  3. In what method(s) should I change to use lazy deletion? Only the delete() method?
  4. If I only change the delete method, how is this picked up by the other methods?
  5. Does the search method look okay?

Here's the rest of the code so you can see what I'm using. I'm really frustrated because I honestly understand how to delete nodes completely way better then this stupid lazy deletion implementation. It's what they teach in the book! lol

Please help... :(


Search Method

So here's my search method:

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

Tree Class

Tree Code (The real deletion method is commented out at the end so I could replace it with the lazy deletion):

package mybinarytreeexample;

public class 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;

回答1:


What changes is that your tree only grows in term of real space used, and never shrinks. This can be very useful if you choose a list as a data-structure to implement your tree, rather than the usual construct Node E {V value; E right; E; left}. I will come back on this later.

I've looked at MANY resources and some say all you need to do is set the node's deleted flag to true. Does this mean that I don't have to worry about the linking after their flag is set?

Yes, if by linking you mean node.left, node.right. Delete simply mark as deleted and that's it. It change nothing else, and it should not, because x.CompareTo(y) must be still working even if x or y are marked as deleted

Is an appropriate way to do this very superficial? As in, just don't let the methods report that something is found if the flag is set to deleted even though the methods do find something?

Well by definition of this method "something" means a node without the deleted flag. Anything with the deleted flag is "nothing" for the user of the tree.

what method(s) should I change to use lazy deletion? Only the delete() method?

Of course not. You already changed the search method yourself. Let's take the isEmpty(). You should keep a counter of deleted nodes and one of total nodes. If they are equal the tree is empty. Otherwise the tree is not.

There is a small bug in your algorithm. When you insert and find out that you land on a deleted node, you just unmark that node. You must also set the value of the node. After all compareTo doesnt insure all fields are strictly equal, just that the objects are equivalent.

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

There might be others.

Side Note:
As said before one instance where this method is useful is a tree backed by an list (let's say array list). With this method the children of element at position i are at position 2*i+1 and 2*i+2. Usually when you delete a node p with children, you replace that node with the leftmost node q of the right subtree (or rightmost node in the left subtree). Here you can just mark p as deleted and swap the value of the deleted node and leftmost. Your array stays intact in memory



来源:https://stackoverflow.com/questions/36613422/what-changes-when-implementing-lazy-deletion-into-a-binary-search-tree-exactly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!