简体   繁体   中英

Deleting a node from a Binary Tree Search

I think there are multiple errors in my code for deleting a node from a BST. I just can't figure out what! Here's my code. Thanks in advance!

void del(int val){
    help = root;
    f = help;
    while (help){
        if(help->data==val) break;
        f  = help;
        if (val > help-> data) help = help->right;
        else help = help->left;
    } if(help->data != val) printf("\nElement not found!");
    else{
        printf("Element found!");
        target = help;
        if(val>f->data){
            if(target->right && !target->left) {f->right = target->right; f = target->right;}
            else {f->right = target->left; f = target->left;}
        } else{
            if(target->right && !target->left) {f->left = target->right; f = target->right;}
            else {f->left = target->left; f = target->left;}
        }
        while(help ->right) help = help->right;
        if(help->left) help = help->left;
        f->right = help;
        free(target);
    }
}

One error that I spot is that if one were to delete the left node in the tree, then the last few lines might not work since they are not symmetric. So, let us say, the tree has root as 6 and left-child as 4 and right-child as 8. Now, you want to delete 4. So, after you have found the node in the first while clause, you would hit the else clause of "if (val > f->data){". At this point, f would point to 6, target and help would point to 4. Now, you are setting the left of f to right of target, so left of 6 would point to NULL and f itself would point to NULL. So, far so good! But, once you get into the while loop, since help has no right node, help would continue to point to 6. In the end, you make the right node of f (btw, f is already NULL at this point) to help and you would actually end up crashing!

while (help->right)
     help = help->right;

if (help->left)
      help = help->left;

f->right = help;

Another error is that you do not update the root pointer, incase you end up deleting the root node.

One simpler approach would be to divide this into three cases. I am providing code for all the three cases. Use a sample tree for each of these three cases and then debug/test it.

First, if the found node (which your file while loop is doing) has no child nodes, then delete it and set its parent to NULL and you are done. Here is a rough-first cut of the first case:

    /* If the node has no children */
    if (!help->left && !help->right) {
        printf("Deleting a leaf node \n");
        f = help->parent;
        if (f) {
            if (value > f->value)
                f->right = NULL;
            else
                f->left = NULL;
        }
        /* If deleting the root itself */
        if (f->value == root) {
            root = NULL;
        }
        free(help);
        return 0;
    }

Second, if the found node has only child (left or right), then splice it out and the child of the found node becomes hte child of the parent node. Here is the second case:

    /* If the node has only one child node */
    if ((help->left && !help->right)
        || (!help->left && help->right)) {
        printf("Deleting a node with only one child \n");
        f = help->parent;

        if (help->left)  {
            child_node = help->left;
        } else  {
            child_node = help->right;
        }

        if (f) {
            if (value > f->value) {
                f->right = child_node;
            } else  {
                f->left = child_node;
            }
        } else {
            /* This must be the root */
            root = child_node;
        }
        free(help);
        return 0;
    }

The third case is tricky -- here the found node has two child nodes. In this case, you need to find the successor of the node and then replace the value of the found node with the successor node and then delete the successor node. Here is the third case:

    /* If the node has both children */
    if (help->left && help->right) {
        successor_found = find_successor(help, help->data);
        printf("Deleting a node with both children \n");
        if (successor_found) {
            successor_value = successor_found->value;
            del(successor_found->value);
            help->value = successor_value;
        }
        return 0;
    }

And, here is the code to find successor:

binary_node_t *node find_successor(binary_node_t *node, int value) {

    binary_node_t *node_found;

    if (!node) {return NULL; }

    node_found = node;
    old_data = node->data;

    /* If the node has a right sub-tree, get the min from the right sub-tree */
    if (node->right != NULL) {
        node = node->right;
        while (node) {
            node_found = node;
            node = node->left;
        }
        return node_found;
    }

    /* If no right sub-tree, get the min from one of its ancestors */
    while (node && node->data <= old_data) {
        node = node->parent;
    }
    return (node);
}
typedef struct xxx {
        struct xxx *left;
        struct xxx *right;
        int data;
        } ;
#define NULL (void*)0
#define FREE(p) (void)(p)

void treeDeleteNode1 (struct xxx **tree, int data)
{
    struct xxx *del,*sub;

        /* Find the place where node should be */
    for (       ; del = *tree; tree = (data < del->data) ? &del->left : &del->right ) {
        if (del->data == data) break;
        }
        /* not found: nothing to do */
    if ( !*tree) return;

        /* When we get here, `*tree` points to the pointer that points to the node_to_be_deleted
        ** If any of its subtrees is NULL, the other will become the new root
        ** ,replacing the deleted node..
        */
    if ( !del->left) { *tree = del->right; FREE(del); return; }
    if ( !del->right) { *tree = del->left; FREE(del); return; }

        /* Both subtrees non-empty:
        ** Pick one (the left) subchain , save it, and set it to NULL */
    sub = del->left;
    del->left = NULL;

        /* Find leftmost subtree of right subtree of 'tree' */
    for (tree =  &del->right; *tree; tree =  &(*tree)->left) {;}
        /* and put the remainder there */
    *tree = sub;
    FREE(del);
}

To be called like:

...
struct xxx *root;
...
treeDeleteNode1( &root, 42);
...

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