参考网址:https://blog.csdn.net/isea533/article/details/80345507
感谢博主的文章,在此申明,代码为本人参考博主对二叉树删除节点的解析所写,实验通过。若有所欠缺,欢迎各位高人指点!!谢谢。
二叉树删除分为三种情况:
1、目标节点没有任何子节点。此时只需接触其与父节点的关系即可。(需要判断目标节点是父节点的左子节点还是右子节点)
if((NULL == tmp->left) && (NULL == tmp->right)) //目标节点没有任何子节点,直接删除//
{
if(tmp == prev->left) //prev为目标节点的父节点地址//
prev->left=NULL;
else if(tmp == prev->right)
prev->right=NULL;
free(tmp);
return head;
}
2、目标节点有一个子节点。让目标节点的父节点与目标节点的子节点建立联系,然后解除目标节点
if(NULL != tmp->left) //目标节点只存在左子节点//
{
if(NULL != prev)
{
if(tmp == prev->left)
prev->left = tmp->left;
else if(tmp == prev->right)
prev->right = tmp->left;
free(tmp);
return head;
}
if(NULL == prev) //目标节点的上一个节点为空,说明该节点为树的根结点,且只有左子节点。//
{
head=tmp->left;
free(tmp);
return head;
}
}
if(NULL != tmp->right) //目标节点只存在右子节点//
{
if(NULL != prev)
{
if(tmp == prev->left)
prev->left = tmp->right;
else if(tmp == prev->right)
prev->right = tmp->right;
free(tmp);
return head;
}
if(NULL == prev)
{
head = tmp->right;
free(tmp);
return head;
}
}
3、目标节点存在左右两个子节点。这个需要根据二叉树的中序排序来分析了,(请参考文件提供的参考链接哈);这里需要说明一下,之所以是根据中序遍历来确认替代的节点,与二叉树左小右大的特点有关,需要找一个折中的值来代替目标节点。
if((NULL != tmp->left) && (NULL != tmp->right)) //目标节点的左右都有子节点,根据中序排序删除//
{
tree *del_tmp=tmp; //记录要删除的节点位置//
// *del_prev=prev;
tmp = tmp->right;
if(NULL == tmp->left) //如果一开始就没有左节点//
{
del_tmp->input_data=tmp->input_data;
if(NULL == tmp->right)
del_tmp->right=NULL;
else
del_tmp->right=tmp->right;
free(tmp);
return head;
}
while(NULL != tmp->left)
{
prev=tmp;
tmp = tmp->left;
}
if(NULL == tmp->right)
prev->left=NULL;
if(NULL != tmp->right)
prev->left=tmp->right;
del_tmp->input_data=tmp->input_data;
free(tmp);
return head;
}
最后,是我的完整代码,可在Linux环境下编译执行。
#include <stdio.h>
#include <stdlib.h>
#define LEN 10
typedef struct Del_tree{
int input_data;
struct Del_tree *left,*right;
}tree;
tree *tree_delNode(tree *head,int del_data); //二叉树删除任意节点//
void test_show(tree *head,int type, int level);
int main(void)
{
tree *new,*tmp=NULL,*head=NULL;
int len;
srand(getpid());
for(len=0;len<LEN;len++)
{
new=malloc(sizeof(tree));
new->input_data=rand()%50+5;
new->left=NULL;
new->right=NULL;
if(NULL == head)
{
head = new;
continue;
}
tmp=head;
while(1)
{
while((NULL != tmp->left)&&(tmp->input_data >= new->input_data))
tmp=tmp->left;
while((NULL != tmp->right)&&(tmp->input_data < new->input_data))
tmp=tmp->right;
if((NULL == tmp->left) && (tmp->input_data >= new->input_data))
{
tmp->left=new;
break;
}
if((NULL == tmp->right) && (tmp->input_data < new->input_data))
{
tmp->right=new;
break;
}
}
}
test_show(head,0,0);
printf("\n");
/*======================节点查找测试========================*/
int find_data;
while(1)
{
printf("输入要删除的节点值:");
scanf("%d",&find_data);
if(0>find_data)
break;
head=tree_delNode(head,find_data);
test_show(head,0,0);
printf("\n");
}
/*==========================================================*/
}
/*====================================================================*/
tree *tree_delNode(tree *head,int del_data)
{
tree *tmp=head,
*prev=NULL; //记录上一个节点地址//
int array_size=0; //数组元素遍历//
/*查找要删除的节点位置*/
while(1)
{
while((tmp->input_data>del_data) && (NULL != tmp->left))
{
prev=tmp;
tmp=tmp->left;
}
while((tmp->input_data<del_data) && (NULL != tmp->right))
{
prev=tmp;
tmp=tmp->right;
}
if((tmp->input_data != del_data) && (NULL == tmp->left) && (NULL == tmp->right))
{
printf("未找到节点!\n");
return head;
}
if(tmp->input_data == del_data)
break;
}
/*====================*/
/*分三种情况删除*/
if((NULL == tmp->left) && (NULL == tmp->right)) //目标节点没有任何子节点,直接删除//
{
if(tmp == prev->left) //prev为目标节点的父节点地址//
prev->left=NULL;
else if(tmp == prev->right)
prev->right=NULL;
free(tmp);
return head;
}
if((NULL != tmp->left) && (NULL != tmp->right)) //目标节点的左右都有子节点,根据中序排序删除//
{
tree *del_tmp=tmp; //记录要删除的节点位置//
// *del_prev=prev;
tmp = tmp->right;
if(NULL == tmp->left) //如果一开始就没有左节点//
{
del_tmp->input_data=tmp->input_data;
if(NULL == tmp->right)
del_tmp->right=NULL;
else
del_tmp->right=tmp->right;
free(tmp);
return head;
}
while(NULL != tmp->left)
{
prev=tmp;
tmp = tmp->left;
}
if(NULL == tmp->right)
prev->left=NULL;
if(NULL != tmp->right)
prev->left=tmp->right;
del_tmp->input_data=tmp->input_data;
free(tmp);
return head;
}
if(NULL != tmp->left) //目标节点只存在左子节点//
{
if(NULL != prev)
{
if(tmp == prev->left)
prev->left = tmp->left;
else if(tmp == prev->right)
prev->right = tmp->left;
free(tmp);
return head;
}
if(NULL == prev) //目标节点的上一个节点为空,说明该节点为树的根结点,且只有左子节点。//
{
head=tmp->left;
free(tmp);
return head;
}
}
if(NULL != tmp->right) //目标节点只存在右子节点//
{
if(NULL != prev)
{
if(tmp == prev->left)
prev->left = tmp->right;
else if(tmp == prev->right)
prev->right = tmp->right;
free(tmp);
return head;
}
if(NULL == prev)
{
head = tmp->right;
free(tmp);
return head;
}
}
/*==============*/
}
/*=================测试打印===========================*/
void test_show(tree *head,int type, int level)
{
tree *tmp=head;
if(NULL == tmp)
return;
int i;
test_show(tmp->right,2,level+1);
switch (type)
{
case 0:
printf("%d\n",tmp->input_data);
break;
case 1:
for (i = 0; i < (level-1)*2; i++)
printf(" ");
printf(" \\\n");
for (i = 0; i < level*2; i++)
printf(" ");
printf("%d\n",tmp->input_data);
break;
case 2:
for (i = 0; i < level*2; i++)
printf(" ");
printf("%d\n",tmp->input_data);
for (i = 0; i < (level-1)*2; i++)
printf(" ");
printf(" /\n");
break;
}
test_show(tmp->left,1,level+1);
}
/*===========================================================*/
附加说明:本人承接Linux系统的嵌入式软件开发项目,CODESYS的runntime组件开发。欢迎加微:wxk101633(备注:委托开发)