从二叉树搜索中删除节点

时间:2013-09-01 04:34:15

标签: c logic binary-search-tree

我认为我的代码中存在多个错误,用于从BST中删除节点。我只是弄不清楚是什么!这是我的代码。提前谢谢!

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);
    }
}

2 个答案:

答案 0 :(得分:0)

我发现的一个错误是,如果要删除树中的左节点,那么最后几行可能不起作用,因为它们不对称。所以,让我们说,树的根为6,左子为4,右子为8.现在,你要删除4.所以,在第一个while子句中找到节点之后,你会命中“if(val> f-> data){”的else子句。此时,f将指向6,目标和帮助将指向4.现在,您将f的左侧设置为目标的右侧,因此6的左侧将指向NULL并且f本身将指向NULL。到现在为止还挺好!但是,一旦你进入while循环,由于help没有正确的节点,help会继续指向6.最后,你创建f的正确节点(btw,f此时已经是NULL)来帮助和你真的会崩溃!

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

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

f->right = help;

另一个错误是您没有更新根指针,因此最终会删除根节点。

一种更简单的方法是将其分为三种情况。我正在为这三种情况提供代码。对这三种情况中的每一种使用样本树,然后对其进行调试/测试。

首先,如果找到的节点(你的文件循环正在进行)没有子节点,那么删除它并将其父节点设置为NULL并完成。这是第一个案例的粗略剪辑:

    /* 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;
    }

其次,如果找到的节点只有子节点(左或右),则将其拼接出来,找到的节点的子节点变为父节点的子节点。这是第二种情况:

    /* 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;
    }

第三种情况很棘手 - 这里找到的节点有两个子节点。在这种情况下,您需要找到节点的后继节点,然后用后继节点替换找到的节点的值,然后删除后继节点。这是第三种情况:

    /* 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;
    }

而且,这是寻找继任者的代码:

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);
}

答案 1 :(得分:0)

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);
}

被称为:

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