简体   繁体   中英

Binary Search Tree Remove

I am working on a binary search tree in C++ at the moment and I have reached the stage where I have to write the remove/delete function(using recursive approach, x = change(x) ). I have two options:

  • to stop at the parent of the node of the node to be deleted;

  • to get to the node to delete and then call a function that will
    return the parent

Approach 1: less expensive, more code

Approach 2: less code, more expensive

Which approach is better according to you, and why?

I disagree that those are your only two options.

I think a simpler solutions is to ask each node weather it should be deleted. If it decides yes then it is deleted and returns the new node that should replace it. If it decides no then it returns itself.

// pseudo code.
deleteNode(Node* node, int value)
{
    if (node == NULL) return node;

    if (node->value == value)
    {
        // This is the node I want to delete.
        // So delete it and return the value of the node I want to replace it with.
        // Which may involve some shifting of things around.
        return doDelete(node);
    }
    else if (value < node->value)
    {
        // Not node. But try deleting the node on the left.
        // whatever happens a value will be returned that
        // is assigned to left and the tree will be correct.
        node->left = deleteNode(node->left, value);
    }
    else
    {
        // Not node. But try deleting the node on the right.
        // whatever happens a value will be returned that
        // is assigned to right and the tree will be correct.
        node->right = deleteNode(node->right, value);
    }
    // since this node is not being deleted return it.
    // so it can be assigned back into the correct place.
    return node;
}

The best approach would be to traverse upto the parent of the node to be deleted, and then delete that child node. Eventually using this approach you always visit the child node, since you always have to confirm the child node is the node u want to delete.

I find that the most efficient form for writing functions for tree data structures in general is the following psuedocode format.

    function someActionOnTree() {
         return someActionOnTree(root)
    }

    function someActionOnTree (Node current) {
         if (current is null) {
              return null
         }
         if (current is not the node I seek) {
              //logic for picking the next node to move to
              next node = ...

              next node = someActionOnTree(next node)
         }
         else {
              // do whatever you need to do with current
              // i.e. give it a child, delete its memory, etc
              current = ...
         }
         return current;
    }

This recursive function recurses over the vertex set of a data structure. For every iteration of the algorithm, it either looks for a node to recurse the function on, and overwrites the data structure's reference to that node with the value of the algorithm's iteration on that node. Otherwise, it overwrites the node's value (and possibly perform a different set of logic). Finally, the function returns a reference to the parameter node, which is essential for the overwriting step.

This is a generally the most efficient form of code I've found for tree data structures in C++. The concepts apply other structures as well - you can use recursion of this form, where the return value is always a reference to a fixed point in the planar representation of your data structure (basically, always return whatever is supposed to be at the spot you're looking at).

Here's an application of this style to a binary search tree delete function to embellish my point.

function deleteNodeFromTreeWithValue( value ) {
     return deleteNodeFromTree(root, value)
}

function deleteNodeFromTree(Node current, value) {
     if (current is null) return null
     if (current does not represent value) {
          if (current is greater than my value) {
               leftNode = deleteNodeFromTree(leftNode, value)
          } else {
                rightNode = deleteNodeFromTree(rightNode, value)
          }
      }
      else {
           free current's memory
           current = null
      }
      return current
}

Obviously, there are many other ways to write this code, but from my experience, this has turned out to be the most effective method. Note that performance isn't really hit by overwriting pointers, since the hardware already cached the nodes. If you're looking into improving performance of your search tree, I'd recommend looking into specialized trees, like self-balancing ones (AVL trees), B-trees, red-black trees, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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