删除二叉搜索树的叶节点 - 分段错误

时间:2012-11-01 11:00:47

标签: c binary-search-tree nodes

我正在尝试删除BST中的叶节点,这是我非递归创建的。问题是,当我试图删除叶节点时,我遇到了一个分段错误,我不清楚它为什么会发生。我相信我评论过的代码导致了这个问题。删除该节点的想法是错误的还是有其他方法从BST删除任何节点?

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

      struct BSTnode
    {
     int data;
     struct BSTnode *left,*right,*parent;

    };

     typedef struct BSTnode node;

     void insert(node **root,int val)
    {
     node *ptr,*newptr;

     newptr=(node *)malloc(sizeof(node));
     newptr->left=NULL;
     newptr->right=NULL;
     newptr->parent=NULL;
     newptr->data=val;

     if((*root)==NULL)
    {
     (*root)=newptr;
     return;
    } 

     ptr=(*root);  

     while(ptr!=NULL && ptr->data!=val)
    {
      if(ptr->data >val )
     {
       if(ptr->left!=NULL)
        ptr=ptr->left;
       else
      {
       ptr->left=newptr;
       newptr->parent=ptr;
       break;
      }
    } 
     else
    {
      if(ptr->right!=NULL)
       ptr=ptr->right;
      else
     {
       ptr->right=newptr;
       newptr->parent=ptr;
       break;
      }
    }
   }

  }

    void deleteLeaf(node **root)
  {

      node *leafParent=NULL;

      if((*root)->left!=NULL)
       deleteLeaf(&((*root)->left));

      if((*root)->right!=NULL)
       deleteLeaf(&((*root)->right));


      if((*root)->left==NULL && (*root)->right==NULL)
     {

      /*  leafParent=(*root)->parent;

          if(leafParent->left==(*root))
           leafParent->left=NULL;
          else
           leafParent->right=NULL;
      */

          free(*root);
        }
      }

 void inorder(node *root)
{
  if(root->left!=NULL)
   inorder(root->left);

  printf(" %d ", root->data);

  if(root->right!=NULL)
   inorder(root->right);
}

 main()
{
 node *root=NULL;
 int i,n,val;

 printf("\n How many elements ?");
 scanf("%d",&n);

 for(i=0;i<n;++i)
{
 scanf("%d",&val);
 insert(&root,val);

}

 printf("\n Inorder traversal : ");
 inorder(root);

 deleteLeaf(&root);
 printf("\n Inorder traversal : ");
 inorder(root);
}

2 个答案:

答案 0 :(得分:0)

确实在deleteLeaf函数中有一些情况,其中(注释掉)leafParent为NULL,然后一旦你用leafParent-&gt;取消引用它,就会出现seg错误。所以你需要按如下方式检查:

    leafParent=(*root)->parent;
    if (leafParent)
    {
        if(leafParent->left==(*root))
        {
            leafParent->left=NULL;
        }
        else
        {
            leafParent->right=NULL;
        }
    }

这样可以防止seg故障,但是我不清楚函数是否会最终完成你想做的事情......换句话说,你的逻辑可能仍然需要一些调整才能让它只删除叶子节点(如果那是你试图做的事情)。

答案 1 :(得分:0)

我相信你并没有真正删除叶子 - 你递归地删除整个树:对于每个节点,你首先删除叶子,然后检查它是否是叶子((left == NULL) && (right == NULL)) - 这显然是从那以后你刚刚删除了它的后代 - 然后将其删除。

第一个问题是,正如Chris快速指出的那样,您没有检查leafParent是否可以变为NULL。检查该节点或为根节点设置父节点,以便不取消引用NULL。另一个(更糟糕的)问题是,一旦释放内存,你就不会使指针失效 - 好的习惯是在释放指针后立即将指针设置为NULL。如果稍后不进行检查,则可以进行段错误,但是当稍后可能由某个其他结构分配内存块时,将不会通过使用指针来静默地破坏内存。您甚至可以编写一个包装器来为您执行此操作(并且它还可以检查释放NULL指针的尝试,这实际上是一个有效的操作,只是默默无效 - 至少在某些平台上)。在这种特殊情况下,一旦你完成删除整个树(就像真正发生的那样),你仍然有指向main()中被删除的根节点的指针 - 你会立即使用它。

作为一个挑剔的旁注,在代码中,int main(void) { ... }int main(int argc, int **argv) { ... }不仅仅是main()。 : - )