我正在尝试删除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);
}
答案 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()
。 : - )