二叉排序树的创建和删除节点

本文介绍了一种二叉搜索树的基本操作实现方法,包括插入、查找和删除节点等核心功能,并通过递归和迭代的方式实现了中序遍历。文章详细解释了每个函数的工作原理及其在实际应用中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stack>
using namespace std;


typedef struct bnode
{
    int data;
    struct bnode *lchild,*rchild;
}BNode,*bitree;


/*如果返回成功,p指向查找成功的那个节点,如果失败就返回查找路径上的最后一个节点,便于我插入*/
int SearchBST(bitree T,int key,bitree f,bitree &p)/*T为根节点,key为要查找的值,f为T的双亲,f的初值为NULL*/
{
    if(!T)
    {
        p=f;//这里必须是f而不能是NULL,因为如果查找不成功p应该指向访问的最后一个节点,这个函数可能会反复递归,所以不能保证f一定是初始值NULL
        return 0;
    }
    else
    {
        if(T->data==key)
        {
            p=T;
            return 1;
        }
        else if(T->data<key)
            return SearchBST(T->rchild,key,T,p);
        else
            return SearchBST(T->lchild,key,T,p);
    }
}


/*插入函数*/
int InsertBST(bitree &T,int key)//这里的T要加引用
{
    bitree p,s;
    if(!SearchBST(T,key,NULL,p))//查找不成功才会插入呀
    {
        s=new BNode[sizeof(BNode)];//注意这种new的写法
        s->data=key;//初始化
        s->lchild=s->rchild=NULL;//初始化
        if(!p)//这里必须考虑到p为空的情况,因为一开始T就是空的,现在我就让T为s
            T=s;//这里也不能写p=s,p是局部变量,函数结束就释放了,而我想改变的是T
        else if(key<p->data)
            p->lchild=s;
        else
            p->rchild=s;
        return 1;
    }
    return 0;
}


/*
删除节点p,这里没有看到f节点是因为我们不对f的左右指针进行改变,而是巧妙的针对p进行一系列修改
这里的删除分为三种情况
(1)左右子树都空:就直接让其父节点的相应指针置空即可
(2)只有左子树或只有右子树:让其父节点的相应指针指向自己的左孩子或者右孩子
(3)左右子树均不空:这里有两种套路,第一种就是先找到p节点中序遍历的直接前驱s,然后将p的父节点f的左指针指向自己的左子树,让s节点的右指针指向自己的右子树;第二种就是让中序遍历的直接前驱或者直接后继代替p自己,然后再删除中序遍历的直接前驱或者直接后继。本文使用第一种方法。
*/


int Del(bitree &p)
{
    bitree q;
    if(!p->lchild&&!p->rchild)//没有子女
    {
        q=p;
        p=NULL;
        delete q;
        return 1;
    }
    if(!p->lchild&&p->rchild)//只有右儿子
    {
        q=p;
        p=p->rchild;
        delete q;
        return 1;
    }
    if(p->lchild&&!p->rchild)//只有左儿子
    {
        q=p;
        p=p->lchild;
        delete q;
        return 1;
    }
    if(p->lchild!=NULL&&p->rchild!=NULL)//左右都有,这里采用的是第一种思路
    {
        q=p->lchild;//q此时是p左子树的根节点
        while(q->rchild)//向右探寻,这个循环结束时候,q指向p中序遍历的直接前驱结点
            q=q->rchild;
        q->rchild=p->rchild;//直接前驱节点的右指针修改为p的右子树
        q=p;//此时q回到p的位置便于我delete
        p=p->lchild;//而p修改为p的左子树,本质是p的父节点的左指针不再指向p而是指向p的左子树
        delete q;
        return 1;
    }
}


/*递归的查找并找到节点删掉*/
int DeleteBST(bitree &T,int key)//这里的T要加引用
{
    if(!T)
        return 0;
    else
    {
        if(T->data==key)
            return Del(T);
        else if(T->data>key)
            return DeleteBST(T->lchild,key);
        else
            return DeleteBST(T->rchild,key);
    }
}


void inorder(bitree bt)//中序遍历
{
    bitree p=bt;
    stack<bitree> s;
    while(p||!s.empty())
    {
        while(p)
        {
            s.push(p);
            p=p->lchild;
        }
        if(!s.empty())
        {
            printf("%d ",s.top()->data);
            p=s.top()->rchild;//这一步别忘了,弹栈之后就要探索p的右子树咯
            s.pop();
        }
    }
    printf("\n");
}


int main()
{
    int n,x,i;
    bitree T;
    while(scanf("%d",&n)!=EOF)
    {
        T=NULL;
        for(i=0;i<n;i++)
        {
            scanf("%d",&x);
            InsertBST(T,x);
        }
        inorder(T);
        printf("chose a number you'd delete:\n");
        scanf("%d",&x);
        DeleteBST(T,x);
        inorder(T);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值