【问题标题】:Delete in Binary search tree in C在C中的二叉搜索树中删除
【发布时间】:2013-03-07 07:29:53
【问题描述】:

我已经在 C 中实现了 BST。插入和查找工作正常。但是删除根节点时删除有问题。我无法释放指向根节点的指针。如果我将它作为双指针传递,我可以,但我想在不使用双指针的情况下保持代码简单。这里我没有指向根节点的头指针。我应该使用指向根节点的头指针吗?

#include<stdio.h>
#include<stdlib.h>
struct node
{
    int data;
    struct node* left;
    struct node* right;
};
struct node* newNode(int data)
{
    struct node* node = malloc(sizeof(struct node));
    node->data=data;
    node->left=NULL;
    node->right=NULL;
    return(node);
}

static int lookup(struct node* node,int target)
{
    if(node==NULL)
    {
        return(0);
    }
    else
    {
        if(target == node->data)
        {
            return(1);
        }
        else
        {
            if(target < node->data)
            {
                return(lookup(node->left,target));
            }
            else
            {
                return(lookup(node->right,target));
            }
        }
    }
}


struct node* insert(struct node* node, int data)
{
    if(node==NULL)
    {
        return(newNode(data));
    }   
    else
    {
        if(data < node->data)
        {
            node->left =insert(node->left,data);
        }
        else
        {
            node->right=insert(node->right,data);
        }
        return(node);
    }
}

struct node* delete(struct node* node, struct node* pnode, int target)
{
    struct node* rchild;
    struct node* rchildparent;
    if(node==NULL)
    {
        return(pnode);
    }
    else
    {
        if(target == node->data)
        {
            if(node->left == NULL && node->right == NULL) //leaf node
            {
                if(pnode == NULL) //special case deleting the root node
                {
                    free(node);
                    return(NULL);
                }
                if(pnode->left == node)
                {
                    pnode->left = NULL;
                }
                else
                {
                    pnode->right = NULL;
                }
                free(node);
                return(pnode);
            }
            if(node->left ==NULL ) //one child
            {
                if(pnode == NULL) //deleting root having no left child
                {
                    struct node* temp = node;
                    node = node->right;
                    free(temp);
                    return(node);
                }
                if(pnode->left == node)
                {
                    pnode->left = node->right;
                }
                else
                {
                    pnode->right = node->right;
                }   
                free(node);
                return(pnode);
            }
            if(node->right ==NULL ) //one child
            {
                if(pnode == NULL) //deleting root having no right child
                {
                    struct node* temp = node;
                    node = node->left;
                    free(temp);
                    return(node);
                }
                if(pnode->left == node)
                {
                    pnode->left = node->left;
                }
                else
                {
                    pnode->right = node->left;
                }   
                free(node);
                return(pnode);
            }

            //two children case
            rchild = node->right;
            rchildparent=node;
            while(rchild->left != NULL)
            {
                rchildparent=rchild;
                rchild = rchild->left;
            }
            node->data=rchild->data;
            if(rchildparent == node)
            {
                //rchildparent->right=rchild->right;
                node->right=rchild->right;
            }
            else
            {
                //rchildparent->left=NULL;
                rchildparent->left=rchild->right;
            }
            free(rchild);
            if(pnode ==NULL) //root node
            {
                return(node);
            }           
            return(pnode);
        }
        else
        {
            if(target < node->data)
            {
                delete(node->left,node,target);
                return(node);
            }
            else
            {
                delete(node->right,node,target);
                return(node);
            }
        }

    }

}
void printinorder(struct node* node)
{
    if(node == NULL)
    {
        return;
    }   
    printinorder(node->left);
    printf("%d\t",node->data);
    printinorder(node->right);
}
int main()
{
    clock_t start,end;
    struct node* root = newNode(3);
    insert(root,7);
    insert(root,7);
    insert(root,7);
    printinorder(root);
    printf("\n");
    root = delete(root,NULL,6);
    printinorder(root);
    printf("\n");
}

编辑: 根据@modifiable lvalue 的建议修复了代码。现在有办法改进删除逻辑吗?

【问题讨论】:

  • 我想函数newNode 中的malloc 没有问题。问题出在delete 函数中,我正在释放指向根节点的指针的本地副本
  • 您将需要一个特殊的 ROOT 指针,该指针需要传递给 delete 函数。另一种解决方案可能是编写一个非递归的delete 函数并使其返回一个node*,这将是新的根。
  • @Koushik 你在说什么?除了 malloc 失败时潜在的 NULL 取消引用,newNode 很好。
  • 如果您的意思是 headPtr 将成为每个节点中的成员,那么可能不会。建议使用父 ptr - 当 parent==this 时可以检查 rootnode

标签: c binary-tree binary-search-tree


【解决方案1】:

我会从删除中返回头节点,并在你的主函数中管理头,例如:root = delete(root, NULL, 10);,我会为插入做同样的事情:root = insert(root,/*...*/);,因为它的一半看起来像你'已经完成了...

【讨论】:

  • 谢谢。这是简单而优雅的。我进行了更改,它适用于我删除根目录的情况。
  • 我认为我最喜欢这个的是,其他人很清楚head 可能确实会改变。我喜欢对可能导致head 更改的任何函数执行此操作(在其他情况下,例如链接列表、队列等)。这样一来,在团队项目和商业环境中出现悬空指针问题的可能性似乎要小得多。在这种情况下,这也可能是一个平衡你的树的机会。
  • 在我的delete 中我仍然不喜欢的一个想法是,每次我检查root 被删除的特殊情况时。我可以通过某种方式避免它以提高性能吗?
  • @arunmoezhi 在我第一次编辑您的代码时,我从delete 代码中删除了不必要的空格:ideone.com/1yVNEP 我通过删除递归元素并按照child、@ 987654330@(一个指针,初始化为&amp;node,但设置为指向在搜索过程中采用的分支)和parent而不是nodepnode我可以删除该测试和许多其他测试以形成这个(未经测试) 代码:ideone.com/HpAOAP
  • 感谢您花时间调试我的代码。其实我也做了一些调试。递归返回有问题。所以我修改了它。现在它几乎适用于所有情况。但我不确定我是否错过了任何..
【解决方案2】:

private DataNode 删除(DataNode root,int dValue){

DataNode temp=null;
if(root!=null){
    if(dValue<root.value){
        root.left=delete(root.left,dValue);
    }
    else if(dValue>root.value){
        root.right=delete(root.right,dValue);
    }
    else{
           if(root.left==null){
                temp=root.right;
               root.right=null;
               return temp;
           }
           else if(root.right==null){
               temp=root.left;
               root.left=null;
               return temp;
           }

           temp=MinBST(root.right);
           root.value=temp.value;
           //deleting inorder successor
           root.right=null;
    }
}
return root;

}

私有DataNode MinBST(DataNode root){

if(root!=null){
    while(root.left!=null){
        root=root.left;
    }
}
return root;

}

通过链接从二叉树中删除节点

https://www.youtube.com/watch?v=YK3tLMYk3nk

【讨论】:

    【解决方案3】:
    //c tree
    #include<stdio.h>
    #include<conio.h>
    struct tree_node
    {
        struct tree_node*right,*left;
        int data;
    };
    struct tree_node*savetemp=NULL;
    struct tree_node* del(struct tree_node*,int);
    struct tree_node* insert(struct tree_node*,int);
    struct tree_node* travel(struct tree_node*,struct tree_node*);
    void inorder(struct tree_node *);
    int height(struct tree_node*);
    int noOfNode(struct tree_node *);
    void main()
    {
        struct tree_node* root=NULL;
        int item,cho;
        clrscr();
        do
        {
            printf("Enter your choice\n");
            printf("1.insert 2.delete 3.display 4.no of nodes 5.height 6.exit\n");
            scanf("%d",&cho);
            switch(cho)
            {
                case 1:{
                    printf("Enter element to insert\n");
                    scanf("%d",&item);
                    root=insert(root,item);
                }
                break;
                case 2:{
                    printf("Enter element to delete\n");
                    scanf("%d",&item);
                    root=del(root,item);
                    if(savetemp!=NULL)//condition for any break link is present to insert or not
                    travel(root,savetemp);//to insert break link during insertion
                }
                break;
                case 3:{
                    printf("inorder travel\n");
                    inorder(root);
                }
                break;
                case 4:{
                    printf("No of nodes are: %d\n",noOfNode(root));
                }
                break;
                case 5:
                printf("height of tree %d",height(root));
                break;
                case 6:
                printf("Exiting");
                break;
                default : printf("wrong cho\n");
            }
        }while(cho!=6);
        getch();
    }
    void inorder(struct tree_node *root)
    {
        if (root != NULL)
        {
        inorder(root->left);
        printf("%d \n", root->data);
        inorder(root->right);
        }
    }
    struct tree_node* insert(struct tree_node*root,int item)
    {
        if(root==NULL)
        {
            struct tree_node* temp;
            temp=(struct tree_node*)malloc(sizeof(struct tree_node));
            temp->left=NULL;
            temp->right=NULL;
            temp->data=item;
            root=temp;
        }
        else
        {
                if(root->data<item)
                {
                    root->right=insert(root->right,item);
                }
                else
                {
                    root->left=insert(root->left,item);
                }
        }
        return(root);
    }
    struct tree_node* del(struct tree_node*root,int item)
    {
        if(item==root->data)
        {
            if(root->left==NULL&&root->right==NULL) //no child
            {
                root=NULL;
    
            }
            else if(root->left==NULL||root->right==NULL) //one child
            {
                if(root->left!=NULL) //left child
                {
                    root=root->left;
                }
                else               //right child
                {
                    root=root->right;
                }
            }
            else  if(root->left!=NULL&&root->right!=NULL) //both child
            {
                struct tree_node* temp;
                savetemp=root->right->left;
                temp=root;
                root=root->right;
                root->left=temp->left;
            }
        }
        else
        {
                if(root->data<item)
                {
                    root->right=del(root->right,item);
                }
                else
                {
                    root->left=del(root->left,item);
                }
        }
        return(root);
    }
    struct tree_node* travel(struct tree_node*root,struct tree_node*savetemp)
    {
        if (savetemp != NULL)
        {
            insert(root,savetemp->data);
            travel(root,savetemp->left);
            travel(root,savetemp->right);
        }
        return(root);
    }
    int height(struct tree_node*root)
    {
        int lheight,rheight;
        if(root==NULL)
        {
            return(-1);
        }
            else
        {
            lheight=height(root->left);
            rheight=height(root->right);
        }
        if(lheight>rheight)
        {
            return(lheight+1);
        }
        else
        {
            return(rheight+1);
        }
    }
    int noOfNode(struct tree_node *root)
    {
    static int count=0;
        if (root != NULL)
        {
        noOfNode(root->left);
        count=count+1;
        noOfNode(root->right);
        }
        return(count);
    }
    

    【讨论】:

    • 请添加更多详细信息
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 2011-11-28
    • 2016-02-18
    • 2017-07-28
    • 1970-01-01
    相关资源
    最近更新 更多