【问题标题】:Delete nodes from binary search tree, without having parent stored inside the structure从二叉搜索树中删除节点,而不将父节点存储在结构中
【发布时间】:2017-01-23 03:29:07
【问题描述】:

作为一个练习,我正在研究二叉搜索树。我已经设法搜索二叉树并添加节点,但现在我试图找到一种删除方法,我似乎陷入了如何确定谁是节点的父节点将被删除。

所以首先我有这个结构

struct BST_node {
    struct double_linked_list *data;
    struct BST_node *left;
    struct BST_node *right;
};

我还有一个指向根的结构的指针..

struct BST_node *BST_email_root = 0;

我有这个功能来搜索节点

struct BST_node *BST_find_customer(struct BST_node *root, char *email) {
if (root==NULL)
    return NULL;
if (strcmp(email,root->data->data->email)==0)
    return root;
else
    {
    if (strcmp(email,root->data->data->email)==-1)
    return BST_find_customer(root->left,email);
    else
        return BST_find_customer(root->right,email);
    }

我在其他函数中调用,通过使用

b = BST_find_customer(BST_email_root, email);

我正在尝试创建删除节点的功能..我要做的是:

struct BST_node *BST_delete(struct BST_node *root, char *email)
    {
    struct BST_node *temp;
    if (root==NULL)
        return root;
    else if(strcmp(root->data->data->email,email)>0)
        root->left = BST_delete(root->left, email);
    else if(strcmp(root->data->data->email,email)<0)
        root->right = BST_delete(root->right, email);
    else
        {
        if(root->left == NULL && root->right == NULL)
            {
            free(root);
            root = NULL;
            }
        else if(root->right == NULL)
            {
            temp = root;
            root = root->left;
            free(temp);
            }
        else if(root->left == NULL)
            {
            temp = root;
            root = root->right;
            free(temp);
            }
        else
            {
            struct BST_node *maxNode = findMaxNode(root->left);//finding the maximum in LEFT sub-tree
            root->data = maxNode->data; //Overwriting the root node with MAX-LEFT
            root->left = BST_delete(root->left, maxNode->data);//deleted the MAX-LEFT node
            }

        return root;
        }

    }

也可以使用这个函数

struct BST_node *findMaxNode(struct BST_node *root)
            {
                if(root->right == NULL) return root;
                findMaxNode(root->right);
            }

但是这也不起作用,我得到错误

【问题讨论】:

  • 尝试保留一个指向您已遍历的上一个节点的指针。

标签: c binary-search-tree


【解决方案1】:

这是一个解决方案,虽然它不是递归的.....

要从 BST 中删除节点 N,需要考虑 3 种情况:

  1. 如果N是叶子,那么没问题,直接删除就行了
  2. 如果 N 只有一个儿子,只需将 N 替换为其儿子;你需要指向 N 的父亲的指针才能做到这一点
  3. 如果 N 有两个儿子,则可以将 N 替换为其右儿子的最左儿子,或由其左儿子的最右儿子替换以保留顺序属性。

    void *BST_delete(struct BST_node *root, char *email){
    
    if (root==NULL)
        return;
    
    struct BST_node * father = NULL;
    char which_son; //will help us in remembering if root is the right or left son of his father
    
    while (strcmp(email,root->data->data->email)!=0){ //first, finding root and remembering who's root father
        if(root==NULL) {
             return ;
        } else if (strcmp(email,root->data->data->email) < 0){
             father = root;
             root = root->left;
             which_son = 'l';
        } else {
             father = root;
             root = root->right;
             which_son = 'r';
        }
    }
        // now you have both the root node, and its father
    if ( (root->right == NULL) && (root->left == NULL) ){ //case 1, if it's a leaf
         free(root);
         return;
    } else if (root->left == NULL) { //case 2 
         if (which_son == 'l') {
             father->left = root->right;
         } else {
             father->right = root->right;
         }
    
    } else { //case 3 : here i get the "rightest" son of root's left son
        struct BSD_node * replacing_node = root->left;
    
        while (replacing_node->right != NULL) {
            replacing_node = replacing_node->right;
        } //now replacing_node is a leaf, and can replace root
        if (which_son == 'l') {
            father->left = replacing_node;
            replacing_node->left = root->left;
            replacing_node->right = root->right;
        } else {
            father->right = replacing_node;
            replacing_node->left = root->left;
            replacing_node->right = root->right;
        }
    }
    free (root);
    } 
    

我将您的函数的返回值更改为 void ,因为它可能不需要任何返回值。

它可以通过简单地将一个节点的“数据”字段替换为另一个节点来以更简单的方式实现,但我故意以这种方式实现它以强调要删除的节点被他的后代之一替换的事实。

如果您认为要抑制的节点应该由其左(右)子的最右(最左)子替换似乎并不明显,请检查这些节点是否是唯一不存在风险的 2 个节点打破你的 BSD 的秩序。

此外,这个函数因单一化而受到很大影响,它会喜欢被重构。

【讨论】:

  • 非常感谢您的回答。我只想返回 BST_EMAIL_root,它只是一个指向二叉树最新节点的指针。我已将您的代码插入到我的完整程序中,但是它似乎效果不太好......现在正在尝试进一步调试它!
  • 我刚刚更正了最后几行,在最后一个 else 语句中用 root 替换了 replace_node,并添加了一个缺少的 return 并会引发 seg_fault ;是的,我是当场写的,我还不是专家,所以如果一两个错误仍然隐藏在其中,我不会感到惊讶,但是在二叉树中抑制节点的精神就在这里。祝你好运!
  • 非常感谢您的帮助!我现在正在尝试检查我的整个代码,但虽然它似乎工作..它并没有真正工作..这让我发疯:)
猜你喜欢
  • 2019-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多