二叉排序树的查找,插入,删除

首先我们需要先了解一下什么叫做引用传递

老规矩先上代码
#include<stdio.h>

//这里我们设了两个引用,一个是b是a的引用,一个是c是b的引用,即a就是b就是c,三者等价
void f1(int&);
void f2(int&);
int main(){
    int a=3;
    f1(a);
    printf("%p\n",&a);
    printf("%d\n",a);		 //最终c改变了a的值
    return 0;
}
void f1(int&b){				//这个符号&前面表示数据类型,其后面表示引用的名字,即b是a的引用(在调试过程中,可以看到在还没有执行语句b=4时,b就有初值为3,也从反面说明了b是a的引用)
    b=4;
    printf("%p\n",&b);
    f2(b);
}

void f2(int&c){				//同理,c是b的引用(在还没有执行c=5时,c已经有初值4了)
    c=5;
    printf("%p\n",&c);
}

最终运行的结果为:

在这里插入图片描述
从结果可以看出,a,b,c三者共用同一存储单元.
最后附上一个详解链接

第二部分即为二叉排序树的代码

#include <stdio.h>
#include <malloc.h>

typedef int Datatype;
//组成二叉排序树需要两个部分,一个是关键字,一个是左,右指针
typedef struct Node
{
    Datatype key;
    struct Node *left, *right;
} NODE;

bool search(NODE *&, Datatype, NODE *, NODE *&);
void insertBST(NODE *&, Datatype);
void deleteBST(NODE *&, Datatype);
void deleteNODE(NODE *&, Datatype);


int main()
{
    NODE *p = NULL;
    insertBST(p, 15);
    insertBST(p, 30);
    insertBST(p, 10);
    insertBST(p, 5);
    insertBST(p, 12);
    insertBST(p, 50);
    insertBST(p, 20);
    insertBST(p, 16);    
    insertBST(p, 25);
    insertBST(p, 28);
    insertBST(p, 26);
    deleteBST(p, 30);
    return 0;
}

/* 如果在二叉排序树中没有找到关键字,则调用insertBST函数
   这里的&表示引用 */
void insertBST(NODE *&T, Datatype key)
{
    NODE *f = NULL;                                 //每次都将f赋值为0(因为每次函数都是从根节点出发,并且默认根节点的父节点为NULL)
    NODE *p;                                        //p指向f所指向的节点(即待插入节点)
    if (!search(T, key, f, p))
    {                                               //search返回false,即没有找到关键字元素,即进行插入操作
        NODE *pNew = (NODE *)malloc(sizeof(NODE));
        pNew->left = pNew->right = NULL;
        pNew->key = key;                            //上面三步都是为了生成一个值为关键字的节点
        if (!p){                                           
            T = pNew;                               //只有一种情况就是空树(即刚开始建树)
        }
        else if (key < p->key){                      //关键字比待插入节点小,则连接到其左子树上                                           
            p->left = pNew;
        }
        else if (key > p->key){
            p->right = pNew;
        }
    }
}

//查找某个元素是否二叉树中(T指向二叉树的根节点,key代表关键字,f指向T的父亲节点,这里的p是引用,即等价于NODE *p中的p)
bool search(NODE *&T, Datatype key, NODE *f, NODE *&p)
{
    if (T == NULL){                                           //两种情况:1.空树(即刚开始建树) 2.递归查询过程中,该节点上无左子树(或右子树)[即查询不到该元素]
        p = f;
        return false;
    }
    else if (key < T->key){                                  //关键字比当前节点元素小,则从当前节点的左子树开始递归查询
        search(T->left, key, T, p);                          //将当前节点左子树节点T->left递归查询(这里的第三项即为f=T,意思是将当前节点T保存在f中,则进行递归查询后f就为此时节点的父节点)
    }
    else if (key > T->key){
        search(T->right, key, T, p);
    }
    else{                                                    //关键字与当前节点相同
        p = T;
        return true;
    }
}


//查找二叉树中是否存在关键字key的节点,这里的&为引用
void deleteBST(NODE *&T, Datatype key)
{
    if (T){
        if (T->key == key){
            deleteNODE(T, key);
        }
        else if (key<T->key){
            deleteBST(T->left, key);
        }
        else deleteBST(T->right, key);
    }
}

/* 删除关键字节点:有四种情况:1.待删节点为叶子节点
                           2.待删节点只有左子树
                           3.待删节点只有右子树
                           4.待删节点既有左子树也有右子树 */
void deleteNODE(NODE *&T, Datatype key)         //这里的T很巧妙,既是待删节点的指针也是其父节点的左或者右指针
{
    NODE *q;                                    //用来保存待删节点的父节点(针对的是最后一种情况)
    NODE *s;                                    //保存待删节点(针对最后一种情况)
    if (T->left == NULL && T->right == NULL){       
        T=NULL;
    }
    else if (T->left == NULL){
        q = T;
        T = T->right;
        free(q);
    }
    else if (T->right == NULL){
        q = T;
        T = T->left;
        free(q);
    }
    else{                                       //此处又分为两种情况:1.待删节点的左子树上没有右子树 2.待删左子树上有右子树
        q = T;
        s = T->left;
        if (!s->right){                         //首先判断待删节点的左子树节点上是否存在右子树
            T = s->left;                        //如果没有右子树,则直接挂上
        }
        else{                                   //第二种情况有右子树,则一直向右移动,找到其最右节点
            while (s->right){
                q = s;
                s = s->right;
            }
            T->key = s->key;                    //将最右节点的值赋给待删节点,然后判断其是否有子树节点
            if (s->left == NULL && s->right == NULL){       //没有子树,则直接赋为空
                free(s);
                q->right = NULL;
            }
            else{                               //有左子树(此时不可能有右子树,因为之前找到的就是最右节点),然后挂上去即可
                q->right = s->left;
                free(s);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值