DataStructure----二叉排序树(详细)

/*********************************************************************
测试数据:二叉排序树为11 8 16 7 9 15 17  二叉排序树为11 8 16 7 10 9 15 17  
         11                                  11
       /   \                                /   \
      8     16                            8     16
    /  \   /  \                         /  \    /  \ 
   7    9 15  17                       7   10  15  17
先序遍历结果为:11 8 7 9 16 15 17            /
删除11之后先序遍历为:9 8 7 16 15 17        9
         9                          先序遍历结果为:11 8 7 10 9 16 15 17  
       /   \                       删除11之后先序遍历为:10 8 7 9 16 15 17
      8     16                              10
    /      /  \                            /   \
   7      15  17                          8     16
                                        /  \    /  \
                                       7    9  15  17
***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#define ENDKEY 0

typedef int KeyType;
typedef struct  node
{
    KeyType  key ;                /* 关键字的值 */
    struct node  *lchild,*rchild; /* 二叉树的左右孩子指针 */
}BSTNode, *BSTree;

void InsertBST(BSTree *t, KeyType key)
/* 若在二叉排序树中不存在关键字等于key的元素,插入该元素 */
{ 
    BSTree s;
    if (*t == NULL)               /* 递归结束条件 */
    {
        s=(BSTree)malloc(sizeof(BSTNode));   /* 申请新的结点s的堆空间 */
        s->key = key;
        s->lchild = NULL; 
        s->rchild = NULL;
        *t=s;
    }
    else 
        if (key < (*t)->key)
            InsertBST(&((*t)->lchild), key);/* 若插入的key的值小于根节点,则将s插入左子树 */
        else 
            InsertBST(&((*t)->rchild), key); /* 反之,将s插入右子树 */
}
/******生成二叉排序树******/
void  CreateBST(BSTree *t)
{
	KeyType key;
    *t = NULL;
    scanf("%d", &key);
    while (key != ENDKEY)   /* 出口条件,ENDKEY预定义为0 */
    {
        InsertBST(t, key);
        scanf("%d", &key);
    }
}
void  PreOrder(BSTree root) /* 递归先序遍历二叉树, root为指向二叉树根结点的指针 */
{
    if (root != NULL)
    {
        printf("%d ", root->key);  /* 输出结点 */
        PreOrder(root->lchild);  /* 先序遍历左子树 */
        PreOrder(root->rchild);  /* 先序遍历右子树 */
    }
}

BSTree  SearchBST(BSTree bst, KeyType key)
/*在根指针bst所指二叉排序树bst上,查找关键字等于key的结点,若查找成功,返回指向该元素结点指针,否则返回空指针*/
{ 
    BSTree q;
    q = bst;
    while(q)
    {
        if (q->key == key) 
            return q;               /* 查找成功 */
        if (q->key > key)  
            q=q->lchild;            /* 在左子树中查找 */
        else  
            q=q->rchild;            /* 在右子树中查找 */
    }
    return NULL;                    /* 查找失败 */
}
BSTNode  *DelBST(BSTree t, KeyType  k) /* 在二叉排序树t中删去关键字为k的结点 */
{
    BSTNode  *p, *f,*s ,*q;
    p = t; 
    f = NULL;
    while(p)                         /* 查找关键字为k的待删结点p */
    { 
        if(p->key == k )  break;     /* 找到则跳出循环 */
        f = p;                         /* f指向p结点的双亲结点 */
        if(p->key > k )  
            p = p->lchild;
        else 
            p = p->rchild;
    } 
    if(p == NULL)  return t;           /* 若找不到,返回原来的二叉排序树 */
    /**************************************
    第一种情况,当被删除的的结点p没有左子树时
    此时p的位置分三种情况:
    First:p为根节点
    Second:p不为根,即有双亲结点,且p为双亲结点f的左子树
    Third:p不为根,即有双亲结点,且p为双亲结点f的右子树
    ***************************************/
    if(p->lchild == NULL)                /* p无左子树 */
    { 
        if(f == NULL)                   /* p是原二叉排序树的根 */
            t = p->rchild;               
        else 
            if(f->lchild == p)           /* p是f的左孩子 */
                f->lchild = p->rchild ;  /* 将p的右子树链到f的左链上 */
            else                       /* p是f的右孩子 */
                f->rchild = p->rchild ;  /* 将p的右子树链到f的右链上 */
            free(p);                   /* 释放被删除的结点p */
    }
    else                               /* p有左子树,即 p->lchild != NULL */
    { 
        q = p; 
        s = p->lchild;                 /* 即左子树的最右下角的最大元素 */
        while(s->rchild)               /* 在p的左子树中查找最右下结点 */
        {
            q = s;                     /* q一直是s结点的前驱 */
            s = s->rchild;             /* s的出口条件是s->rchlid = null */
        }
/***********************************************************************
       找到最右下结点,由于此节点为最大值的结点,所有此节点必无右结点
                  *****但是对于被删除的P结点而言存在两种情况:*****
                              **
                              **
                              **
                              **
                           *  **  *
                            * ** *
                             ****
First:p的左节点不存在右孩子,如下图:(举例:删除下图的11,即被删结点p=11)
直接将p结点的左孩子指,q节点的左孩子,从而替换掉p
然后free(s),即可完成.
q==p--->   11                   8
        /      \              /   \
 s---> 8       16            7     16          
     /         /  \               /  \ 
   7          15  17             15  17

***********************************************************************
Second:p的左节点存在右孩子(举例:删除下图的11,即被删结点p=11)
此时将q==p不成立,则将11被10替换,然后q的右孩子指向s的左孩子
(s若没有左孩子的话,情况一样,即指向null)
然后free(s),即可完成.
   p--->   11                    10
        /       \              /    \
 q---> 8        16            8     16           
     /    \     /  \        /  \    /  \ 
   7 s---> 10  15  17      7    9  15  17
          /
         9

    p--->   11                    10
        /       \              /    \
 q---> 8        16            8     16           
     /    \     /  \        /       /  \ 
   7 s---> 10  15  17      7       15  17
          /
        NULL
************************************************************************/
        if(q == p)      
            q->lchild = s->lchild;
        else 
            q->rchild = s->lchild;      /*将s的左子树链到q上*/  
        p->key = s->key;                 /*将s的值赋给p*/
        free(s);
    }
    return t;
}

void main()
{
    BSTree T;
    int k;
    BSTree result;
	printf("----输入零即退出----\n");
    printf("建立二叉排序树,请输入序列:\n");
    CreateBST(&T);                    /*创建二叉树*/

    printf("先序遍历输出序列为:");
    PreOrder(T);

    printf("\n请输入要查找的元素:");
    scanf("%d",&k);
    result = SearchBST(T,k);
    if (result != NULL)
        printf("要查找的元素为:%d\n", result->key);
    else
        printf("未找到!\n");

    result = DelBST(T,k);            /*删除结点k*/

	printf("查找完毕后,先序遍历输出序列为:");
    PreOrder(result);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值