二叉搜索树的实现

二叉搜索树(BinarySortTree),又称二叉查找树、二叉排序树。它或者是一棵空树;或者是具有下列性质的二叉树:
1.若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2.若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3.左、右子树也分别为二叉排序树。若子树为空,查找不成功。
(本文对二叉搜索树的删除作详细解释)
代码实现:
头文件:
BSTree.h

#pragma once
#include<assert.h>
#include<malloc.h>
#include<stdio.h>
#include<stdlib.h>

typedef int Datatype;
typedef struct BSTreeNODE
{
    struct BSTreeNODE* pleft;
    struct BSTreeNODE* pright;
    Datatype data;
}Node, *PNode;

void Init(PNode *proot);                       //初始化
PNode BuyNode(Datatype data);                  //申请新节点
int Insert(PNode* proot, Datatype data);       //插入
void Inorder(PNode proot);                     //中序遍历(二叉搜索树中序遍历结果有序)
PNode Find(PNode proot, Datatype data);        //查找
int Delete(PNode *proot, int data);            //删除
void DestroyBSTree(PNode* proot);              //销毁

void Test();

源文件:
BSTree.c

void Init(PNode *proot)
{
    assert(proot);
    *proot = NULL;
}

PNode BuyNode(Datatype data)
{
    PNode pnewnode = (PNode)malloc(sizeof(Node));
    assert(pnewnode);
    pnewnode->data = data;
    pnewnode->pleft = NULL;
    pnewnode->pright = NULL;
    return pnewnode;
}

void Inorder(PNode proot)
{
    if (proot)
    {
        Inorder(proot->pleft);
        printf("%d ", proot->data);
        Inorder(proot->pright);
    }
}
int Insert(PNode *proot, Datatype data)//不允许插入相同关键字
{
    PNode pcur = NULL;
    PNode parent = NULL;
    assert(proot);
    if (NULL == *proot)
        *proot = BuyNode(data);

    //找位置
    pcur = *proot;
    while (pcur)
    {
        if (data < pcur->data)
        {
            parent = pcur;
            pcur = pcur->pleft;
        }
        else if (data > pcur->data)
        {
            parent = pcur;
            pcur = pcur->pright;
        }
        else
            return 0;
    }
    pcur = BuyNode(data);
    if (data < parent->data)
        parent->pleft = pcur;
    else
        parent->pright = pcur;
    return 1;
}



PNode Find(PNode proot, Datatype data)
{
    PNode pcur = proot;
    while (pcur)
    {
        if (data == pcur->data)
            return pcur;
        else if (data < pcur->data)
            pcur = pcur->pleft;
        else
            pcur = pcur->pright;
    }
    return NULL;
}

删除可分为四种情况
1.搜索树为空,直接返回
2.搜索树没有右孩子(包括有左孩子的节点和叶子节点)
①根节点:5号节点
这里写图片描述
部分代码:

pdel = pcur;
if (pcur == *proot)
{
    pdel = *proot;
    *proot = pcur->pleft;
}

②非根节点:如1号和4号节点
这里写图片描述
部分代码:

if (pcur == parent->pleft)
    parent->pleft = pcur->pleft;//1
else
    parent->pright = pcur->pleft;//4

3.没有左孩子(包括有右孩子的节点和空节点)
①根节点:5号节点
这里写图片描述
部分代码:

pdel = pcur;
if (pcur == *proot)
{
    pdel = *proot;
    *proot = pcur->pright;
}

②非根节点:6号和8号节点
这里写图片描述
部分代码:

if (parent->pleft = pcur) //6
{
    parent->pleft = pcur->pright;
}
else
    parent->pright = pcur->pright;//8

4.有左右孩子
思路:找到结点p的中序直接前驱结点s,把结点s的数据转移到结点p,然后删除结点s,由于结点s为p的左子树中最右的结点,因而s无右子树,所以接下来方法和第二种情况类似。
部分代码:

        parent = pcur;
        pdel = pcur->pleft;
        while (pdel->pright)
        {
            parent = pdel;
            pdel = pdel->pright;
        }
        pcur->data = pdel->data;
        if (pcur == parent)
        {
            parent->pleft = pdel->pleft;
        }
        else
        {
            parent->pright = pdel->pleft;
        }

删除部分总代码:

int Delete(PNode *proot, int data)
{
    assert(proot);
    PNode pcur = NULL;
    PNode pdel = NULL;
    PNode parent = NULL;
    if (NULL == *proot)
        return 0;
    pcur = *proot;
    while (pcur)
    {
        if (data == pcur->data)
            break;
        else if (data < pcur->data)
        {
            parent = pcur;
            pcur = pcur->pleft;
        }
        else
        {
            parent = pcur;
            pcur = pcur->pright;
        }
    }
    if (NULL == pcur)
    {
        return 0;
    }
    //只有左孩子 || 叶子节点
    if (NULL == pcur->pright)
    {
        pdel = pcur;
        if (pcur == *proot)
        {
            pdel = *proot;
            *proot = pcur->pleft;
        }
        else
        {
            if (pcur == parent->pleft)
                parent->pleft = pcur->pleft;//1
            else
                parent->pright = pcur->pleft;//4
        }

    }
    //只有右孩子 || 叶子节点
    else if (NULL == pcur->pleft)
    {
        pdel = pcur;
        if (pcur == *proot)
        {
            pdel = *proot;
            *proot = pcur->pright;
        }
        else
        {
            if (parent->pleft = pcur) //6
            {
                parent->pleft = pcur->pright;
            }
            else
                parent->pright = pcur->pright;//8
        }
    }
    else
    {
        parent = pcur;
        pdel = pcur->pleft;
        while (pdel->pright)
        {
            parent = pdel;
            pdel = pdel->pright;
        }
        pcur->data = pdel->data;
        if (pcur == parent)
        {
            parent->pleft = pdel->pleft;
        }
        else
        {
            parent->pright = pdel->pleft;
        }
    }
        free(pdel);
    return 1;
}

销毁 , 测试代码:

void DestroyBSTree(PNode* proot)
{
    assert(proot);
    free(proot);
    proot = NULL;
}

void Test()
{
    int a[] = { 5,3,4,1,7,8,2,6,0,9 };
    int i = 0;
    PNode proot = NULL;
    Init(&proot);
    for (; i < sizeof(a) / sizeof(a[0]); i++)
    {
        Insert(&proot, a[i]);
    }

    Inorder(proot);

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值