二叉排序树

定义及描述
二叉排序树(Binary Sort Tree)也称二叉查找树,是一种特殊的二叉树。
二叉排序树或者是一棵空树;
或者具有下列性质:
(1)若左子树不空,则左子树中所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树中所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
结点结构体定义:

typedef struct NODE
{
    int key;
    struct NODE *Lchild;
    struct NODE *Rchild;
}BstNode, *BsTree;

二叉排序树的插入

  • 若二叉树为空。则首先单独生成根结点。

  • 若二叉树非空,则将插入值与二叉排序树根结点的关键字进行比较:
    a.如果key的值等于根结点的值,则停止插入;
    b.如果key的值小于根结点的值,则将结点插入左子树;
    c.如果key的值大于根结点的值,则将结点插入右孩子。

  • 注意:新插入的结点总是叶子结点。
    题目:已知序列5,4,8,1,9,7,6,2,12,11,10,3,按照此顺序构造二叉排序树

这里写图片描述
程序清单:

//创建有序二叉树时的插入算法
void Ins_BsTree(BsTree *root, int key)
{
    BstNode *Bsnode;
    if (*root == NULL)
    {
        Bsnode = (BstNode*)malloc(sizeof(BstNode));
        Bsnode->key = key;
        Bsnode->Lchild = NULL;
        Bsnode->Rchild = NULL;
        *root = Bsnode;
    }
    else if (key < (*root)->key)
    {
        Ins_BsTree(&((*root)->Lchild), key);
    }
    else if (key>(*root)->key)
    {
        Ins_BsTree(&((*root)->Rchild), key);
    }
}

//创建二叉排序树
void CreateBsTree(BsTree *Bst)
{
    int input = 0;
    printf("请输入数据建立二叉树,输入“-1”结束。\n");
    scanf("%d", &input);
    while (input != -1)
    {
        Ins_BsTree(Bst, input);//调用插入算法将新输入的数据有序的插入到二叉树中
        scanf("%d", &input);
    }
}

二叉排序树的查找
因为二叉排序树可看做是一个有序表,所以在二叉排序树上进行查找,和折半查找类似,也是一个逐步缩小查找范围的过程。
算法思想:首先将待查关键字key与根结点关键字t进行比较,如果:

  • key = t:则返回根结点地址
  • key < t:进一步查左子树
  • key > t:进一步查右子树
    程序清单:
//二叉树的查找
BstNode* SearchBstree(BsTree Bsroot, int key)
{
    //二叉树为NULL,查找不到,返回NULL
    if (Bsroot == NULL)
    {
        return NULL;
    }
    //查找到,返回该结点
    if (Bsroot->key == key)
    {
        return Bsroot;
    }
    //比根结点的值大,在右子树上查找
    else if (key > Bsroot->key)
    {
        SearchBstree(Bsroot->Rchild, key);
    }
    //比根结点的值小,在左子树上查找
    else
    {
        SearchBstree(Bsroot->Lchild, key);
    }
}

二叉排序树的删除
设在二叉排序树被删除结点是p,其双亲结点为f。(假设结点p是结点f的左孩子)
情况讨论:
(1) 若p为叶结点,则可直接将其删除:f->lchild = NULL;free(p);
这里写图片描述
(2) 若p结点只有左子树或只有右子树,则可将p的左子树或右子树直接改为其双亲结点f的左子树:f->lchild = p->lchild;free(p);
这里写图片描述
(3) 若p既有左子树又有右子树,此时有两种处理方法:
方法1:首先找到p结点在中序序列中的直接前驱结点s,然后将p的左子树改为f的左子树,而将p的右子树改为s的右子树:f->lchild = p->lchild;s->rchild = p->rchild;free(p);
方法2:首先找到p结点在中序序列中的直接前驱结点s,然后用s结点的值替代p结点的值,再将s结点删除,原s结点的左子树改为s的双亲结点q的右子树:p->data = s->data;q->rchild = s->lchild;free(s);
程序清单:
这里写图片描述

//删除(p为待删除结点,p可能是叶子结点,可能只有左子树或右子树,或者左右子树都有)
BstNode* DeleteBstree(BsTree Bsroot, int key)
{
    BstNode *p = Bsroot;
    BstNode *f = NULL;    //f是p的父结点
    BstNode *q, *s;       //q是s的父结点,s是q的直接前驱
    //不断查找直到找到目标结点,直接删除
    while (p != NULL)
    {
        if (key == p->key)
        {
            break;
        }
        f = p;         //f记录p的父结点位置
        if (key < p->key)        //待删除的结点<根结点值,继续在左子树上查找
        {
            p = p->Lchild;
        }
        else if (key>p->key)     //待删除的结点>根结点值,继续在右子树上查找
        {
            p = p->Rchild;
        }
    }
    //没有查找到,返回原二叉树
    if (p == NULL)
    {
        return Bsroot;
    }
    //p没有左孩子(将p的右孩子置为f的左孩子或者右孩子,然后直接删除p)
    if (p->Lchild == NULL)
    {
        if (f == NULL)   //p没有父结点,即p为二叉树根结点
        {
            p = p->Rchild;
        }
        else if (f->Lchild == p)//p是f的左孩子
        {
            f->Lchild = p->Rchild;  //将p的右孩子置为f的左孩子
        }
        else if (f->Rchild == p)//p是f的右孩子
        {
            f->Rchild = p->Rchild;  //将p的右孩子置为f的右孩子
        }
        free(p);  //删除p
        p = NULL;
    }
    else  //p有左孩子
    {
        q = p;
        s = p->Lchild;
        while (s->Rchild)//在p的左子树上查找最右边的结点,即为中序序列中p的直接前驱
        {
            q = s;    //q记录s的父结点位置
            s = s->Rchild;
        }
        if (q == p)//待删除的结点是它直接前驱的父结点
        {
            q->Lchild = s->Lchild;
        }
        else
        {
            q->Rchild = s->Lchild;
        }
        p->key = s->key;   //用s的值覆盖掉待删除结点的值
        free(s);
    }
    return Bsroot;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值