C语言实现二叉排序树,并实现插入与删除操作。

通过学习我们可以知道:顺序表便于搜索,但是不便于插入与删除;而链表便于插入和删除却不便于搜索,那么有没有比较折中的数据结构呢?答案就是:二叉排序树。二叉排序树既有数组的有点也有链表的优点,非常适合处理大批量的动态数据。

二叉排序树的定义:

  1. 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  3. 左、右子树也分别为二叉排序树;
  4. 没有键值相等的结点。

二叉排序树的结构定义:

typedef struct BiTNode
{
    int data ;
    struct BiTNode *lchid , *rchild ;
}BiTNode , *BiTree ;

二叉排序树的查找操作:
如果树中有与key相等的元素,那么返回这个结点的地址,如果没有与key相等的结点,那么返回在沿着查找key路径上的最后一个结点的地址。因为这棵树可能是空树,f的初始值应该设置为NULL。

Status SearchBST( BiTree T , int key , BiTree f , BiTree *p )
{
    if( T == NULL )
    {
        *p = f ;
        return FALSE ;
    }
    else if( key == T->data )
    {
        *p = T ;
        return OK ;
    }
    else if( key < T->data )
        return SearchBST( T->lchid , key , T , p ) ;
    else
        return SearchBST( T->rchild , key , T , p ) ;
}

插入操作:

Status InsertBST( BiTree *T , int val )
{
    BiTree p , s ;
    if( !SearchBST( *T , val , NULL , &p ) )//树中不能存在与val相等的结点
    {
        s = ( BiTNode * )malloc( sizeof( BiTNode ) ) ;
        s->data = val ;
        s->lchid = s->rchild = NULL ;
        if( p == NULL )
            *T = s ;
        else if( p->data > val )
            p->lchid = s ;
        else
            p->rchild = s ;
        return OK ;
    }
    else
        return FALSE ;
}

删除操作:

这个比较就会比较麻烦一点。
在这里插入图片描述
当我们要删除18时,我们只需要把结点20的左孩子指针指向结点15就行了。
在这里插入图片描述
当我们要删除结点22时,同样的道理:只需要把结点20的右孩子指针指向结点24就可以了。

我们再来看一个二叉排序树:
在这里插入图片描述

如果这个时候我们要删除结点10呢?是直接把结点19的左,右孩子指针分别指向结点6和结点15吗?
在这里插入图片描述
看图我们知道:结点15是结点19的右孩子,若按照二叉排序树的定义,结点19的右孩子必须比19大,显然这里15是违反了这个规定的。
那么该怎么办呢?
5 6 8 10 12 13 14 15 16 19 20 21 22 24,这是在未删除结点10的时候,二叉排序树对数据的排序结果。既然结点19不能代替结点10的位置,那么这个时候我们就要找这个排序中里最接近结点10的结点来代替10,有两个选择:结点8或者结点12,这两个的方法的实现几乎一样,这里就讲用结点8代替结点10的情况。

既然结点8是结点10的前驱,那么我们就应该在结点10的左子树中查找结点8的位置。
再综合上面分析的三种情况考虑:
对于要删除的结点:

  1. 只有左子树
  2. 只有右子树
  3. 既有右子树又有左子树

用结点10的前驱结点8来代替结点10:

Status Delete( BiTree *p )
{
    BiTree q ;
    if( ( *p )->lchid == NULL )
    {
        q = *p ;
        *p = ( *p )->rchild ;
        free( q ) ;
    }

    else if( ( *p )->rchild == NULL )
    {
        q = *p ;
        *p = ( *p )->lchid ;
        free( q ) ;
    }
    else
    {
        BiTree s ;
        q = *p ;
        s = ( *p )->lchid ;
        while( s->rchild )
        {
            q = s ;
            s = s->rchild ;
        }
        ( *p )->data = s->data ;
        if( q != ( *p ) ) 
            q->rchild = s->lchid ;
        else //这个情况表示的是:要删除的结点的左孩子没有右子树的情况
            ( *p )->lchid = s->lchid ;
        free( s ) ;
    }
    return OK ;

看图更易于理解:
在这里插入图片描述

用结点10的后继结点12的操作与上述的大同小异:

Status Delete( BiTree *p )
{
    BiTree q ;
    if( ( *p )->lchid == NULL )
    {
        q = *p ;
        *p = ( *p )->rchild ;
        free( q ) ;
    }

    else if( ( *p )->rchild == NULL )
    {
        q = *p ;
        *p = ( *p )->lchid ;
        free( q ) ;
    }

    else
    {
        BiTree s ;
        q = *p ;
        s = ( *p )->rchild ;
        while( s->lchid )
        {
            q = s ;
            s = s->lchid ;
        }

        ( *p )->data = s->data ;

        if( q != ( *p ) )
            q->lchid = s->rchild ;
        else
            q->rchild = s->rchild ;

        free( s ) ;
    }
    return OK ;
}

通过二叉排序树的定义可以知道,数据的顺序输出其实就是树的中序遍历:

void InorderTraverse( BiTree T )
{
    if( T == NULL )
        return ;
    else
    {
        InorderTraverse( T->lchid ) ;
        printf( "%d " , T->data ) ;
        InorderTraverse( T->rchild ) ;
    }
}

最后附上源代码:

#include<stdio.h>
#include<stdlib.h>
#define FALSE 0
#define OK 1

typedef int Status ;

typedef struct BiTNode
{
    int data ;
    struct BiTNode *lchid , *rchild ;
}BiTNode , *BiTree ;

Status SearchBST( BiTree T , int key , BiTree f , BiTree *p ) ;
Status InsertBST( BiTree *T , int val ) ;
void InorderTraverse( BiTree T ) ;
Status Delete( BiTree *p ) ;
Status DeleteBST( BiTree *T , int key ) ;

int main( void )
{
    int i ;
    BiTree T = NULL ;
    int Array[ 14 ] = { 13  , 15 ,  16 , 5 , 6 , 8 , 10 , 14 , 12 ,  19 , 20 , 21 ,  22 ,  24   } ;
    for( i = 0 ; i < 14 ; i++ )
    {
        InsertBST( &T , Array[ i ] ) ;
    }

    InorderTraverse( T ) ;  printf( "\n" ) ;
    DeleteBST( &T , 10 ) ;
    InorderTraverse( T ) ;  printf( "\n" ) ;

    return 0 ;
}

Status SearchBST( BiTree T , int key , BiTree f , BiTree *p )
{
    if( T == NULL )
    {
        *p = f ;
        return FALSE ;
    }
    else if( key == T->data )
    {
        *p = T ;
        return OK ;
    }
    else if( key < T->data )
        return SearchBST( T->lchid , key , T , p ) ;
    else
        return SearchBST( T->rchild , key , T , p ) ;
}

Status InsertBST( BiTree *T , int val )
{
    BiTree p , s ;
    if( !SearchBST( *T , val , NULL , &p ) )
    {
        s = ( BiTNode * )malloc( sizeof( BiTNode ) ) ;
        s->data = val ;
        s->lchid = s->rchild = NULL ;

        if( p == NULL )
            *T = s ;

        else if( p->data > val )
            p->lchid = s ;
        else
            p->rchild = s ;
        return OK ;
    }
    else
        return FALSE ;
}

void InorderTraverse( BiTree T )
{
    if( T == NULL )
        return ;
    else
    {
        InorderTraverse( T->lchid ) ;
        printf( "%d " , T->data ) ;
        InorderTraverse( T->rchild ) ;
    }
}

Status Delete( BiTree *p )
{
    BiTree q ;
    if( ( *p )->lchid == NULL )
    {
        q = *p ;
        *p = ( *p )->rchild ;
        free( q ) ;
    }

    else if( ( *p )->rchild == NULL )
    {
        q = *p ;
        *p = ( *p )->lchid ;
        free( q ) ;
    }

    else
    {
        BiTree s ;
        q = *p ;
        s = ( *p )->lchid ;
        while( s->rchild )
        {
            q = s ;
            s = s->rchild ;
        }

        ( *p )->data = s->data ;

        if( q != ( *p ) )
            q->rchild = s->lchid ;
        else
            ( *p )->lchid = s->lchid ;

        free( s ) ;
    }
    return OK ;
}


Status DeleteBST( BiTree *T , int key )
{
    if( *T == NULL )
        return FALSE ;

    else
    {
        if( key == ( *T )->data )
            return Delete( T ) ;
        else if( key > ( *T )->data )
            return DeleteBST( &( *T )->rchild , key ) ;
        else
            return DeleteBST( &( *T )->lchid , key ) ;
    }

}
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值