二叉搜索树删除功能两次删除相同的东西

Posted

技术标签:

【中文标题】二叉搜索树删除功能两次删除相同的东西【英文标题】:binary search tree delete function deleting the same thing twice 【发布时间】:2022-01-23 05:33:32 【问题描述】:

我正在尝试创建一个删除 bst 中最左边的 2 个节点的二叉搜索树。出于某种原因,我的代码删除了第一个值两次,而不是移动到下一个。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

struct treeNode 
    char *word;                         // the string word that is stored
    int origin;                         // position of the word in the original text input’s line 1
    struct treeNode *left;              // pointer for the left children of the node
    struct treeNode *right;             // pointer for the right children of the node
    struct treeNode *parent;            // pointer for the parent of the node
;
typedef struct treeNode NODE;

NODE *
addNode(NODE * r, char *x)

    // r = root pointer of the tree
    // x = value to add into this tree
    // return the root of the updated tree
    NODE *p = malloc(sizeof(NODE));

    p->word = malloc(strlen(x) + 1);
    strcpy(p->word, x);                 // strcpy input: (destination, data to be copied)
    // printf("%s", x);
    p->parent = NULL;
    p->left = NULL;
    p->right = NULL;

// if tree is empty, tree consists of p only
    if (r == NULL)
        return p;

    if (strcmp(x, r->word) > 0) 

        r->right = addNode((r->right), x);
        return r;
    
    else 
        // add new node the left subtree
        r->left = addNode((r->left), x);
        return r;
    

    return r;



NODE *
getLeftMostNode(NODE * root)

    // return the pointer to the right most node
    if (root == NULL)
        return NULL;
    NODE *p = root;

    while (p->left != NULL)
        p = p->left;
    return p;


NODE *
addTree2Tree(NODE * X, NODE * Y)

    if (X == NULL)
        return Y;
    if (Y == NULL)
        return X;

    X = addNode(X, Y->word);
    X = addTree2Tree(X, Y->left);
    X = addTree2Tree(X, Y->right);
    return X;


NODE *
removeNode(NODE * r)

// remove any node that store value x from tree
// r: root pointer of this tree
// return root pointer of the updated tree after removal

    NODE *p = getLeftMostNode(r);

    NODE *C = p->parent;
    NODE *A = p->left;
    NODE *B = p->right;

    if (C == NULL) 
        // p is root of the tree
        free(p);
        return addTree2Tree(A, B);      // add tree A and tree B and return the new combination tree
    
    if (A != NULL) 
        // make A a child of C assuming position of P
        if (p == C->left)
            C->left = A;
        else
            C->right = A;
        A->parent = C;
        free(p);
        return addTree2Tree(r, B);
    
    if (B != NULL) 
        if (p == C->left)
            C->left = B;
        else
            C->right = B;
        B->parent = C;
        free(p);
        return r;
    
    if (p == C->left)
        C->left = NULL;
    else
        C->right = NULL;
    free(p);                            // free allocation for p
    return r;



void
printArray(NODE * r)


// print all the values on the tree rooted at node "r" // print in alphabetical order

// if the tree is empty, return // print all the values on the tree rooted at node "r" // print in the in-order order: print left first, followed by root, followed by right values

    if (r == NULL) 
        return;
    

    else 

        printArray(r->left);            // print all values in left subtree
        printf("%s ", r->word);
        printArray(r->right);           // print all values in right subtree

    


int
main()

    // input must be implemented by linked list, not array
    NODE *root = NULL;
    int ch;
    char in[1000];                      // input array
    int len = 0;
    char del[100];                      // word to be deleted
    char word[1000];

    while ((ch = getchar()) != '\n')
        in[len++] = ch;
    in[len] = '\0';
    // printf("%s\n", in);

    int i = 0,
        j = 0;

    while (i <= len) 
        // space to store a word
        if ((in[i] == ' ') || (in[i] == '\0') || (in[i] == '\t')) 
            word[j] = '\0';             // end of word
            j = 0;
            root = addNode(root, word);
            // printf("%s\n", word);
        
        else
            word[j++] = in[I];
        i++;

    
    int k = 0;

    removeNode(root);
    removeNode(root);

    printArray(root);
    printf("\n");

    return 0;

这是我得到的错误

【问题讨论】:

为什么addNode会递归分配多个节点然后泄露? 即使不看removeNode,我们也可以看出removeNode(root); 显然是错误的。如果树中只剩下一个节点怎么办? root 需要修改。 提示:p-&gt;word = malloc(strlen(x) + 1); strcpy(p-&gt;word, x);可以简化为p-&gt;word = strdup(x); 【参考方案1】:

函数removeNode 正在寻找parent,但parent 从未在addNode 中分配。你想分配r-&gt;right-&gt;parent = r;r-&gt;left-&gt;parent = r;

BST 不保留重复键。如果strcmp(x, r-&gt;word) == 0,则不要添加新节点。

addNode 也应该更正,如果rNULL,函数会立即返回新节点。

NODE* addNode(NODE* r, char* x)

    if(!x) 
        return NULL;

    if (!r)
    
        NODE* p = malloc(sizeof(NODE)); if (!p) return NULL;
        p->word = strdup(x);
        p->parent = NULL;
        p->left = NULL;
        p->right = NULL;
        return p;
    

    if (strcmp(x, r->word) > 0) 
    
        r->right = addNode((r->right), x);
        r->right->parent = r;
        return r;
    
    else if (strcmp(x, r->word) < 0)
    
        r->left = addNode((r->left), x);
        r->left->parent = r;
        return r;
    

    return r;

修改插入函数,使root 只分配一次:

while (i <= len) 

    if ((in[i] == ' ') || (in[i] == '\0') || (in[i] == '\t')) 
    
        word[j] = '\0';             
        j = 0;
        if(!root)
            root = addNode(root, word);
        else
            addNode(root, word);
    
    else
        word[j++] = in[i];
    i++;

仔细检查指针以确保避免使用NULL 指针。例如:

NODE* removeNode(NODE* r)

    if(!r)
        return NULL;
    NODE* p = getLeftMostNode(r);
    if(!p)
        return NULL;
    ...

我尚未检查其余代码,但该示例将适用于所做的这些更改。

【讨论】:

以上是关于二叉搜索树删除功能两次删除相同的东西的主要内容,如果未能解决你的问题,请参考以下文章

二叉搜索树(KV模型,二叉搜索树删除节点)

二叉树二叉搜索树

C++-二叉搜索树的查找&插入&删除-二叉搜索树代码实现-二叉搜索树性能分析及解决方案

⭐算法入门⭐《二叉树 - 二叉搜索树》中等05 —— LeetCode 450. 删除二叉搜索树中的节点

数据结构—二叉树如何删除一个结点二叉树排序树和二叉搜索树的遍历

Leetcode 450.删除二叉搜索树的节点