二叉排序树的实现+判别(C语言)(西工大数据结构)

239 阅读6分钟

今天运动会开幕式结束!国旗班顺利收关!这一阵学习落下很多,以后得花很多时间在学习上了。但也很开心圆满完成国旗班任务。 今天的题目并不很难,主要想把二叉排序树实现下,也方便我以后复习使用。

二叉排序树

定义

 二叉排序树(BST),也叫二叉查找树。二叉排序树或者是一颗空树,
 或者是一颗具有下列特性的非空二叉树:

       1.若左子树非空,则左子树上所有结点关键字值均小于根结点的关键字值

       2.若右子树非空,则右子树上所有结点关键字值均大于根结点的关键字值

       3.左、右子树本身也分别是一颗二叉排序树。
对二叉排序树进行中序遍历,可以得到一个递增的有序序列。

例: 在这里插入图片描述

操作

定义

typedef struct BinTreeNode
{
    int data;
    struct BinTreeNode *Lchild;
    struct BinTreeNode *Rchild;
}BinTreeNode,*BinTree;

建立

注意此处要用两个函数(输入-1结束)


void InsertBinTree(BinTreeNode **T,int elem)//插入二叉排序树结点(因为要从上往下一步一步找,所以一次只能插一个,不能递归)
{
    if(*T==NULL)
    {
       *T=(BinTreeNode*)malloc(sizeof(BinTreeNode));
       (*T)->data=elem;
       (*T)->Lchild=NULL;
       (*T)->Rchild=NULL;
    }
    else if(elem<(*T)->data)
        InsertBinTree(&((*T)->Lchild),elem);
    else if(elem>(*T)->data)
        InsertBinTree(&((*T)->Rchild),elem);

}

void CreateBinTree(BinTreeNode **T)
{
    int elem;
    (*T)=NULL;
    scanf("%d",&elem);
    while(elem!=-1)
    {
        InsertBinTree(T,elem);
        scanf("%d",&elem);
    }
}

查找

查找单个元素

BinTreeNode* SelectTree(BinTreeNode *T,int elem)//查找二叉排序树中的元素
{
    if(T==NULL) return NULL;
    else if(T->data==elem) return T;
    else if(T->data>elem) return (SelectTree(T->Lchild,elem));
    else return (SelectTree(T->Rchild,elem));

查找范围内元素

void SelectRangeelem(BinTreeNode *T,int a,int b)
{
    if(T)
    {
        SelectRangeelem(T->Lchild,a,b);
        if(T->data>a&&T->data<b) printf("%d ",T->data);
        SelectRangeelem(T->Rchild,a,b);
    }
}

删除

void DelBST(BinTreeNode *T,int key)//在二叉排序树中删除结点
{//因为一个结点一旦有左子树,就要有区分左右大小的任务,所以以有无左子树来分类讨论
    BinTreeNode *p,*f,*s,*q;
    p=T;
    f=NULL;
    while(p)//查找为key的待删除结点
    {
        if(p->data==key) break;//找到则break
        f=p;//f指向p的双亲结点
        if(p->data>key) p=p->Lchild;
        else p=p->Rchild;
    }
    if(p==NULL) return ;//找不到则退出
    if(p->Lchild==NULL)//若p无左子树
    {
        if(f==NULL) free(p);//p为原树的根
        else if(f->Lchild==p)//p为f的左子树
            f->Lchild=p->Rchild;//把p的右子树链到f的左子树上
        else//p为f的右子树
            f->Rchild=p->Rchild;//把p的右子树链到f的右子树上
        free(p);
    }
    else//p有左子树
    {
        q=p;
        s=q->Lchild;
        while(s->Rchild)
        {
            q=s;
            s=s->Rchild;//在p的左子树中查找最右下结点(此节点为首个比待删除结点小的结点,它能肩负起区分大小的任务)
        }
        if(q==p) q->Lchild=s->Lchild;
        else q->Rchild=s->Lchild;//把s的左子树链到s的双亲结点p的右子树(绕开s)
        p->data=s->data;
        free(s);
    }

}

判断是否为二叉排序树

int SelectBinSortTree(BinTreeNode *T)//判断是否为二叉排序树
{
    if(T==0) return 1;
    else if(T->Lchild&&T->Rchild)
    {
        if(T->data<T->Lchild->data||T->data>T->Rchild->data) return 0;
        else return(SelectBinSortTree(T->Lchild)&&SelectBinSortTree(T->Rchild));
    }
    else if(T->Lchild)
    {
        if(T->data<T->Lchild->data) return 0;
        else return(SelectBinSortTree(T->Lchild));
    }
    else if(T->Rchild)
    {
        if(T->data<T->Rchild->data) return 0;
        else return(SelectBinSortTree(T->Rchild));
    }
    return 1;
}

总体测试代码如下

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

typedef struct BinTreeNode
{
    int data;
    struct BinTreeNode *Lchild;
    struct BinTreeNode *Rchild;
}BinTreeNode,*BinTree;

void CreateTree(BinTreeNode **T)//建立二叉树
{
    int elem;
    scanf("%d",&elem);
   if(elem==-1) *T=NULL;
     else{
            *T=(BinTreeNode*)malloc(sizeof(BinTreeNode));
            (*T)->data=elem;
        CreateTree(&((*T)->Lchild));
        CreateTree(&((*T)->Rchild));
     }
}

void InsertBinTree(BinTreeNode **T,int elem)//插入二叉排序树结点(因为要从上往下一步一步找,所以一次只能插一个,不能递归)
{
    if(*T==NULL)
    {
       *T=(BinTreeNode*)malloc(sizeof(BinTreeNode));
       (*T)->data=elem;
       (*T)->Lchild=NULL;
       (*T)->Rchild=NULL;
    }
    else if(elem<(*T)->data)
        InsertBinTree(&((*T)->Lchild),elem);
    else if(elem>(*T)->data)
        InsertBinTree(&((*T)->Rchild),elem);

}

void CreateBinTree(BinTreeNode **T)//建立树
{
    int elem;
    (*T)=NULL;
    scanf("%d",&elem);
    while(elem!=-1)
    {
        InsertBinTree(T,elem);
        scanf("%d",&elem);
    }
}

BinTreeNode* SelectTree(BinTreeNode *T,int elem)//查找二叉排序树中的元素
{
    if(T==NULL) return NULL;
    else if(T->data==elem) return T;
    else if(T->data>elem) return (SelectTree(T->Lchild,elem));
    else return (SelectTree(T->Rchild,elem));
}

void SelectRangeelem(BinTreeNode *T,int a,int b)//查找范围内元素
{
    if(T)
    {
        SelectRangeelem(T->Lchild,a,b);
        if(T->data>a&&T->data<b) printf("%d ",T->data);
        SelectRangeelem(T->Rchild,a,b);
    }
}


int SelectBinSortTree(BinTreeNode *T)//判断是否为二叉排序树
{
    if(T==0) return 1;
    else if(T->Lchild&&T->Rchild)
    {
        if(T->data<T->Lchild->data||T->data>T->Rchild->data) return 0;
        else return(SelectBinSortTree(T->Lchild)&&SelectBinSortTree(T->Rchild));
    }
    else if(T->Lchild)
    {
        if(T->data<T->Lchild->data) return 0;
        else return(SelectBinSortTree(T->Lchild));
    }
    else if(T->Rchild)
    {
        if(T->data<T->Rchild->data) return 0;
        else return(SelectBinSortTree(T->Rchild));
    }
    return 1;
}

void printOrder(BinTreeNode *T)//输出树
{
    if(T==NULL)return;
    printOrder(T->Lchild);
    printf("%d ",T->data);
    printOrder(T->Rchild);
}

void DelBST(BinTreeNode *T,int key)//在二叉排序树中删除结点
{//因为一个结点一旦有左子树,就要有区分左右大小的任务,所以以有无左子树来分类讨论
    BinTreeNode *p,*f,*s,*q;
    p=T;
    f=NULL;
    while(p)//查找为key的待删除结点
    {
        if(p->data==key) break;//找到则break
        f=p;//f指向p的双亲结点
        if(p->data>key) p=p->Lchild;
        else p=p->Rchild;
    }
    if(p==NULL) return ;//找不到则退出
    if(p->Lchild==NULL)//若p无左子树
    {
        if(f==NULL) free(p);//p为原树的根
        else if(f->Lchild==p)//p为f的左子树
            f->Lchild=p->Rchild;//把p的右子树链到f的左子树上
        else//p为f的右子树
            f->Rchild=p->Rchild;//把p的右子树链到f的右子树上
        free(p);
    }
    else//p有左子树
    {
        q=p;
        s=q->Lchild;
        while(s->Rchild)
        {
            q=s;
            s=s->Rchild;//在p的左子树中查找最右下结点(此节点为首个比待删除结点小的结点,它能肩负起区分大小的任务)
        }
        if(q==p) q->Lchild=s->Lchild;
        else q->Rchild=s->Lchild;//把s的左子树链到s的双亲结点p的右子树(绕开s)
        p->data=s->data;
        free(s);
    }

}


int main()
{
    BinTreeNode *T;

    CreateTree(&T);
    //CreateBinTree(&T);
    printOrder(T);
    DelBST(T,12);
    printOrder(T);
    //BinTreeNode *Tfind;
    //Tfind=SelectTree(T,48);
    //printf("  %d",Tfind->data);
    //if(SelectBinSortTree(T))
    //{
    //    printf("yes");
    //}
   // else printf("no");
    return 0;
}

(读者根据需求自行测试便可)

题目(二叉排序树的判别)

在这里插入图片描述 在这里插入图片描述

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

typedef struct BinTreeNode
{
    int data;
    struct BinTreeNode *Lchild;
    struct BinTreeNode *Rchild;
}BinTreeNode,*BinTree;

void CreateBinTree(BinTreeNode **T)//建立二叉树
{
    int elem;
    scanf("%d",&elem);
   if(elem==-1) *T=NULL;
     else{
            *T=(BinTreeNode*)malloc(sizeof(BinTreeNode));
            (*T)->data=elem;
        CreateBinTree(&((*T)->Lchild));
        CreateBinTree(&((*T)->Rchild));
     }
}



int SelectBinSortTree(BinTreeNode *T)//判断
{
    if(T==0) return 1;
    else if(T->Lchild&&T->Rchild)
    {
        if(T->data<T->Lchild->data||T->data>T->Rchild->data) return 0;
        else return(SelectBinSortTree(T->Lchild)&&SelectBinSortTree(T->Rchild));
    }
    else if(T->Lchild)
    {
        if(T->data<T->Lchild->data) return 0;
        else return(SelectBinSortTree(T->Lchild));
    }
    else if(T->Rchild)
    {
        if(T->data<T->Rchild->data) return 0;
        else return(SelectBinSortTree(T->Rchild));
    }
    return 1;
}

void printOrder(BinTreeNode *T)
{
    if(T==NULL)return;
    printOrder(T->Lchild);
    printf("%d ",T->data);
    printOrder(T->Rchild);
}

int main()
{
    BinTreeNode *T;
    
    CreateBinTree(&T);
    //printOrder(T);
    if(SelectBinSortTree(T))
    {
        printf("yes");
    }
    else printf("no");
    return 0;
}

在这里插入图片描述 我们中序输出: 在这里插入图片描述 可见为递增有序数列。