C语言实现二叉树的节点删除

参考网址: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(备注:委托开发)

  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值