以下是二叉树删除节点的代码,C Primer Plus 第5版中的第17章的原代码
bool DeleteItem(const Item *pi,Tree *ptree)
{
Pair look;
look=SeekItem(pi,ptree);
if(look.child==NULL)
return false;
if(look.parent==NULL) /*删除根项目 */
DeleteNode(&ptree->root);
else if(look.parent->left==look.child)
DeleteNode(&look.parent->left);
else
DeleteNode(&look.parent->right);
ptree->size--;
return true;
}
static void DeleteNode(Node **ptr)
/*ptr 是指向目标节点的父节点指针成员的地址 */
{
Node *temp;
puts((*ptr)->item.petname);
if((*ptr)->left==NULL)
{
temp=*ptr;
*ptr=(*ptr)->right;
free(temp);
}
else if((*ptr)->right==NULL)
{
temp=*ptr;
*ptr=(*ptr)->left;
free(temp);
}
else /*被删成员有两个子节点 */
{
/*找到右子树的依附位置 */
for(temp=(*ptr)->left;temp->right!=NULL;temp=temp->right)
continue;
temp->right=(*ptr)->right;
temp=*ptr;
*ptr=(*ptr)->left;
free(temp);
}
}
Pair类型的声明如下:
typedef struct pair
{
Node *parent;
Node *child;
} Pair;
Node类型的声明如下:
typedef struct node{
Item item;
struct node *left;
struct node *right;
}Node;
原来想着DeleteItem()函数中,删除节点调用的是通过if语句后调用DeleteNode(&look.parent->right)或(&look.parent->left),
而不直接调用(&look.child);自作聪明的将原代码中的DeleteItem()函数修改后如下:
bool DeleteItem(const Item *pi,Tree *ptree)
{
Pair look;
look=SeekItem(pi,ptree);
if(look.child==NULL)
return false;
if(look.parent==NULL) /*删除根项目 */
DeleteNode(&ptree->root);
else
DeleteNode(&look.child)
ptree->size--;
return true;
}
发现程序不能正确删除节点。调试过程中,发现DeleteNode()函数返回前,*ptr已经指向了他的一个子树,但是函数返回后,发现ptree里面对应的节点指向了一段乱码。想来想去终于想明白,原来&look.child值是look.child指针所在的地址,而&look.prarent->left值是树中某个节点的地址。使用&look.child做为参数时,DeleteNode()函数处理完后,look.child值被修改,而树中的节点指向的地址并未修改。但是该地址的数据已被释放,故会显示乱码。使用&look.parenet->left(right)时,修改的就是树中某个节点的值。能达到预期目的。
大学时,老师曾说过指针是C语言的精髓。现在看来,精髓不是那么容易掌握的。
2018年6月6日,大学毕业后的第14个年头,花费了2个月的空闲时间后,终于看完了人生第一本编程书籍《C PrimerPlus》第五版,自己所学虽非计算机专业,但一直对编程有这特别的向往,工作以来断断续续看过一些书,但一直没完整看完过一本,今天中午看完第一本,回想2个月来每天晚上熬夜到0点的坚持,不由感叹万分。今天留个记号,以后继续加油。
bool DeleteItem(const Item *pi,Tree *ptree)
{
Pair look;
look=SeekItem(pi,ptree);
if(look.child==NULL)
return false;
if(look.parent==NULL) /*删除根项目 */
DeleteNode(&ptree->root);
else if(look.parent->left==look.child)
DeleteNode(&look.parent->left);
else
DeleteNode(&look.parent->right);
ptree->size--;
return true;
}
static void DeleteNode(Node **ptr)
/*ptr 是指向目标节点的父节点指针成员的地址 */
{
Node *temp;
puts((*ptr)->item.petname);
if((*ptr)->left==NULL)
{
temp=*ptr;
*ptr=(*ptr)->right;
free(temp);
}
else if((*ptr)->right==NULL)
{
temp=*ptr;
*ptr=(*ptr)->left;
free(temp);
}
else /*被删成员有两个子节点 */
{
/*找到右子树的依附位置 */
for(temp=(*ptr)->left;temp->right!=NULL;temp=temp->right)
continue;
temp->right=(*ptr)->right;
temp=*ptr;
*ptr=(*ptr)->left;
free(temp);
}
}
Pair类型的声明如下:
typedef struct pair
{
Node *parent;
Node *child;
} Pair;
Node类型的声明如下:
typedef struct node{
Item item;
struct node *left;
struct node *right;
}Node;
原来想着DeleteItem()函数中,删除节点调用的是通过if语句后调用DeleteNode(&look.parent->right)或(&look.parent->left),
而不直接调用(&look.child);自作聪明的将原代码中的DeleteItem()函数修改后如下:
bool DeleteItem(const Item *pi,Tree *ptree)
{
Pair look;
look=SeekItem(pi,ptree);
if(look.child==NULL)
return false;
if(look.parent==NULL) /*删除根项目 */
DeleteNode(&ptree->root);
else
DeleteNode(&look.child)
ptree->size--;
return true;
}
发现程序不能正确删除节点。调试过程中,发现DeleteNode()函数返回前,*ptr已经指向了他的一个子树,但是函数返回后,发现ptree里面对应的节点指向了一段乱码。想来想去终于想明白,原来&look.child值是look.child指针所在的地址,而&look.prarent->left值是树中某个节点的地址。使用&look.child做为参数时,DeleteNode()函数处理完后,look.child值被修改,而树中的节点指向的地址并未修改。但是该地址的数据已被释放,故会显示乱码。使用&look.parenet->left(right)时,修改的就是树中某个节点的值。能达到预期目的。
大学时,老师曾说过指针是C语言的精髓。现在看来,精髓不是那么容易掌握的。
2018年6月6日,大学毕业后的第14个年头,花费了2个月的空闲时间后,终于看完了人生第一本编程书籍《C PrimerPlus》第五版,自己所学虽非计算机专业,但一直对编程有这特别的向往,工作以来断断续续看过一些书,但一直没完整看完过一本,今天中午看完第一本,回想2个月来每天晚上熬夜到0点的坚持,不由感叹万分。今天留个记号,以后继续加油。