搜索二叉树节点的查找与删除 (C语言)

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


/*创建一颗 搜索二叉树 结构体*/
typedef struct TreeNode{
    int data;
    struct TreeNode *leftTree;
    struct TreeNode *rightTree;
}TreeNode;

/*中序递归遍历*/    /* 递归的本质是压栈 */
void mid_travel(TreeNode *Node)
{
    if(Node)   /*如果节点不为空,就进入*/
    {
        mid_travel(Node->leftTree);
        printf("%d ",Node->data);
        mid_travel(Node->rightTree);
    }
}

/*往树中插入数据*/
void insertNode(TreeNode **r,int data)
{
    TreeNode *t = (*r);
    if((*r) == NULL)  /*刚开始是空树;创建树*/
    {
        /*申请一个空间,用来存储根节点*/
        *r = (TreeNode *)malloc(sizeof(TreeNode));
        /*初始化根节点*/
        (*r)->data = data;
        (*r)->leftTree = (*r)->rightTree = NULL;
    }
    else  /*如果不是空树,插入子树*/
    {
        /*因为下面不在涉及指向问题了,所以不再使用(*r),转而用t 代替*/
        while(1)
        {
           /*搜索二叉树,必须按照一定的顺序插入*/
            if(data > t->data)    /*大于,在右*/
            {
                if(t->rightTree == NULL)
                {
                    /*先创建一块空间,然后初始化   和创建根节点的方法一样*/
                    t->rightTree = (TreeNode *)malloc(sizeof(TreeNode));
                    t->rightTree->data = data;
                    t->rightTree->leftTree = t->rightTree->rightTree = NULL;
                    break;
                }
                /*如果不为空,指向下一个节点,然后继续往下执行。如果data <= t->data
                  执行下面的。如果不是,通过wile(1),再执行上面的*/
                t = t->rightTree;
            }
            else
            {
                if(t->leftTree == NULL)
                {
                    /*创建内存,并初始化*/
                    t->leftTree = (TreeNode *)malloc(sizeof(TreeNode));
                    t->leftTree->data = data;
                    t->leftTree->leftTree = t->leftTree->rightTree = NULL;
                    break;
                }
                t = t->leftTree;
            }
        }
    }
}
/*搜索二叉树 添加节点 的 递归写法*/
void inser_node(TreeNode **r,int data)
{
    if((*r)==NULL)
    {
        /*创建树根*/
        (*r) = (TreeNode*)malloc(sizeof(TreeNode));
        (*r)->data = data;
        (*r)->leftTree = (*r)->rightTree = NULL;
    }
    else
    {
        if(data > (*r)->data)
            inser_node(&(*r)->rightTree,data);
        else
            inser_node(&(*r)->leftTree,data);
    }
}

/*搜索二叉树节点  非递归*/
TreeNode * searchNode(TreeNode *Node,int find)
{
    while(Node)
    {
        if(find == Node->data)
            return Node;
        else if(find > Node->data)
            Node = Node->rightTree;
        else
            Node = Node->leftTree;
    }
    /*没有找到。返回NULL*/
    return NULL;
}

/*搜索二叉树节点  递归写法*/
TreeNode *search_Node(TreeNode* Node,int data)
{
    if(Node)
    {
        if(data == Node->data)
            return Node;
        else if(data > Node->data)  /*分情况递归,加return*/
            return search_Node(Node->rightTree,data);
        else
            return search_Node(Node->leftTree,data);
    }
    return NULL;
}

/*搜索二叉树的最大节点    找最右*/
TreeNode * max_Node(TreeNode *Node)
{
    if(Node)
    {
        while(Node->rightTree)
        {
            Node = Node->rightTree;
        }
        return Node;
    }
    /*如果没找到,返回NULL*/
    return NULL;
}
/*搜索二叉树的最小节点  找最左*/
TreeNode *minNode(TreeNode *Node)
{
    if(Node)
    {
        while(Node->leftTree)
        {
            Node = Node->leftTree;
        }
        return Node;
    }
    return NULL;
}
/*搜索二叉树的当前节点的父节点*/
TreeNode *parent_Node(TreeNode *root,TreeNode *child)
{
    /*递归中的静态变量*/
   static TreeNode *parent = NULL;
   // TreeNode *parent = NULL;
    if(root)
    {
        if(root->leftTree == child || root->rightTree == child)
            parent = root;
        else
        {
            parent_Node(root->leftTree,child);
            parent_Node(root->rightTree,child);
        }
    }
    return parent;
}
/*删除二叉树的节点*/
/*删除逻辑:分三种情况删除:
 *第一种情况:若为叶子节点,直接删除( 根叶子节点 要单独处理) 
 *第二种情况:若该节点有一个子节点,左节点或右节点 。找到他的父节点,
 *让父节点指向左节点或右节点(若该节点为根,要单独处理 )
 *第三种情况:有两个子节点   */
void delNode(TreeNode **r,TreeNode *del)
{
    if((*r)==NULL || del == NULL)   return ;
    TreeNode *parent;         /*父节点*/
    TreeNode *root = *r;      /*定义变量,用来存储跟节点的地址*/
    TreeNode *minRight;       /*给两个子节点的情况使用*/
    
    /*情况一:叶子节点的情况  分为 普通叶子节点 和 跟叶子节点 的情况*/
    if(del->leftTree==NULL && del->rightTree==NULL)
    {
        /* 跟叶子节点 */
        if((*r) == del)
        {
            free(root);
            (*r)=NULL;
         /*return一定要加,否则就要继续执行了*/
            return ;
        }
        /*其他跟叶子节点*/
        else
        {
            parent = parent_Node(root,del);
            if(parent->leftTree == del)
                parent->leftTree = NULL;
            else
                parent->rightTree = NULL;
            free(del);
        }
    }
    /*第二种情况  只有一个节点的情况  先分析只有左节点的情况*/
    else if(del->leftTree != NULL && del->rightTree == NULL)
        {
            if((*r) == del)   /*再分成两种情况  删除节点是 根节点 和 非根节点*/
            {
                (*r) = del->leftTree/*或者是这样root->leftTree*/;
                free(del/*root*/);
                return;
            }
            else
            {
                /*找到父节点*/
                parent = parent_Node(root,del);
                /*确定要删除的节点是父节点的 左节点 还是 右节点*/
                if(parent->leftTree == del)
                    parent->leftTree = del->leftTree;
                else
                    parent->rightTree = del->leftTree;
                free(del);
                return;
            }
        }
        /*再分析第二种情况中,只有右节点的情况*/
        else if(del->leftTree == NULL && del->rightTree != NULL)
        {
            /*方法和上面一样*/
            if(root == del)
            {
                (*r) = del->rightTree;
                free(del);
                return;
            }
            /*找到父节点*/
            parent = parent_Node(root,del);
            if(parent->leftTree == del)
                parent->leftTree = del->leftTree;
            else
                parent->rightTree = del->leftTree;
            free(del);
        }
        /*第三种情况  左右节点都有*/
        else
        {
/*通常情况下(也就是他的右面还有分支的情况),找他右面最小的节点(这个节点一定是没有左节点,右节点可有可无),
* 将这个节点和待删除节点互换
* 另外,这个节点一定有父节点(是他的右上节点),将父节点直接和最小节点的右节点连接*/
            minRight = minNode(del->rightTree);
            del->data = minRight->data;
            parent = parent_Node(root,minRight);
            if(minRight != del->rightTree)/*这种情况的判断*/
                parent->leftTree = minRight->rightTree;
         /*特殊情况,右侧是一条线的情况   此时,parent = pdel */
            else
                parent->rightTree = minRight->rightTree;
            /*删除最小的*/
            free(minRight);
        }
    }


/*按照中序遍历的顺序,输出搜索二叉树的当前节点的的下一个节点*/

/*销毁树     递归实现*/
void destroy_tree(TreeNode *root)
{
    if(root)
    {
        destroy_tree(root->leftTree);
        destroy_tree(root->rightTree);
        free(root);
    }
}
int main(void)
{
    /*不赋初值,运行没效果*/
    TreeNode *root = NULL;
    int data[]={6,2,8,1,5,3,4};
    int i = 0,num =7;

    for(i=0;i<num;i++)
    {
        inser_node(&root,data[i]);
    }
    /*中序遍历*/
    mid_travel(root);


    TreeNode *findB;
    TreeNode *min;
    TreeNode *max;
    TreeNode *par;
    /*递归查找*/
    findB = searchNode(root,2);
    if(findB)
        printf("\nfind=%d \n ",findB->data);
    else
        printf("\n not find \n");

    /*搜索最小节点*/
    min = minNode(root);
    printf("min=%d;\n",min->data);
    /*搜索最大节点*/
    max = max_Node(root);
    printf("max=%d;\n",max->data);


    /*搜索二叉树的当前节点的父节点*/
    par = parent_Node(root,findB);
    printf("parent=%d \n ",par->data);

    /*删除二叉树的节点*/
    delNode(&root,findB);
    /*中序遍历*/
    mid_travel(root);

    return 0;
}


  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

One Piece&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值