基于二叉排序树的基本操作

 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根节点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
以下为二叉排序树的实例和结点结构

//二叉排序树的结点结构
typedef struct Node{
   ElemType val;
   struct Node *LChild,*RChild;
}Node;
二叉排序树的插入
1、找出被插结点的父亲结点。
2、判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
3、若二叉树为空。则首先单独生成根结点。
//在二叉排序树中插入一个关键字为value的结点
int Insert(Node *root,int value){
  Node *p=root,*q=NULL,*par=NULL;
  int mark=0;
  while(p!=NULL&&mark==0){//找到value应插入的父节点
      par=p;
      if(p->val==value){
        mark=1;
      }else if(p->val>value){
        p=p->LChild;
      }else if(p->val<value){
        p=p->RChild;
      }
  }
  if(mark==1)  return 0;//存在value则不插入
  q=(Node *)malloc(sizeof(Node));
  q->val=value;
  q->LChild=q->RChild=NULL;
  if(root==NULL){
     root=q;
  }else if(par->val>q->val){//判断插入其左右子树
     par->LChild=q;
  }else{
     par->RChild=q;
  }
  return 1;
}
二叉排序树的查找,像其他树的查找一样遍历结点
//查找关键字为key的结点,返回指向该结点的指针
Node *Search(Node *root,int key){
  Node *p=NULL;
  if(root==NULL){
    return NULL;
  }
  p=root;
  while(p){
    if(p->val==key){
      return p;
    }else if(p->val>key){//当前节点的值大于key则去结点的左子树查找
      p=p->LChild;
    }else{
      p=p->RChild;
    }
  }
  return p;
}
二叉排序树的删除
1、若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则可以直接删除此子结点。
2、若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。
3、若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。
//从二叉排序树中删除值为value的结点并重新连接它的左或右子树
int Delete(Node *root,int value){
  Node *s,*p,*q;
  p=Search(root,value);//查找value的结点
  if(p==NULL) return 1;//没有找到
  if(!p->RChild){//右子树空则只需重接它的左子树
    q=p;
    p=p->LChild;
    free(p);
  }else if(!p->LChild){//左子树空则只需重接它的右子树
    q=p;
    p=p->RChild;
    free(p);
  }else{//左右子树均不空
    q=p;
    s=p->RChild;
    while(s->LChild){//转右,然后向左到尽头
      q=s;
      s=s->LChild;
    }
    p->val=s->val;//s指向被删结点的前驱
    if(q!=p){
      q->LChild=s->RChild;
    }else{
      q->LChild=s->LChild;
    }
    free(s);
  }
  return 0;
}

以下为完整程序
#include<stdio.h>
#define N 100
typedef int ElemType;
//二叉排序树的结点结构
typedef struct Node{
   ElemType val;
   struct Node *LChild,*RChild;
}Node;
Node *BitRepTr;
//查找关键字为key的结点,返回指向该结点的指针
Node *Search(Node *root,int key){
  Node *p=NULL;
  if(root==NULL){
    return NULL;
  }
  p=root;
  while(p){
    if(p->val==key){
      return p;
    }else if(p->val>key){//当前节点的值大于key则去结点的左子树查找
      p=p->LChild;
    }else{
      p=p->RChild;
    }
  }
  return p;
}
//在二叉排序树中插入一个关键字为value的结点
int Insert(Node *root,int value){
  Node *p=root,*q=NULL,*par=NULL;
  int mark=0;
  while(p!=NULL&&mark==0){//找到value应插入的父节点
      par=p;
      if(p->val==value){
        mark=1;
      }else if(p->val>value){
        p=p->LChild;
      }else if(p->val<value){
        p=p->RChild;
      }
  }
  if(mark==1)  return 0;//存在value则不插入
  q=(Node *)malloc(sizeof(Node));
  q->val=value;
  q->LChild=q->RChild=NULL;
  if(root==NULL){
     root=q;
  }else if(par->val>q->val){//判断插入其左右子树
     par->LChild=q;
  }else{
     par->RChild=q;
  }
  return 1;
}
//从二叉排序树中删除值为value的结点并重新连接它的左或右子树
int Delete(Node *root,int value){
  Node *s,*p,*q;
  p=Search(root,value);//查找value的结点
  if(p==NULL) return 1;//没有找到
  if(!p->RChild){//右子树空则只需重接它的左子树
    q=p;
    p=p->LChild;
    free(p);
  }else if(!p->LChild){//左子树空则只需重接它的右子树
    q=p;
    p=p->RChild;
    free(p);
  }else{//左右子树均不空
    q=p;
    s=p->RChild;
    while(s->LChild){//转右,然后向左到尽头
      q=s;
      s=s->LChild;
    }
    p->val=s->val;//s指向被删结点的前驱
    if(q!=p){
      q->LChild=s->RChild;
    }else{
      q->LChild=s->LChild;
    }
    free(s);
  }
  return 0;
}
//中序遍历二叉排序树
void MidOrder(Node *root){
  if(root!=NULL){
     MidOrder(root->LChild);
     printf("%d ",root->val);
     MidOrder(root->RChild);
  }
}
int main(){
  Node *root,*p;
  int k,i,val,n,num[N];
  printf("首先建立二叉排序树\n");
  printf("请输入结点个数\n");
  scanf("%d",&n);
  if(n<1){
    return -1;
  }
  root=(Node *)malloc(sizeof(Node));
  printf("输入各节点的关键字值,以空格间隔\n");
  scanf("%d",&num[0]);
  root->val=num[0];
  root->LChild=NULL;
  root->RChild=NULL;
  for(i=1;i<n;i++){
    scanf("%d",&num[i]);
    Insert(root,num[i]);
  }
  printf("对二叉排序树进行的中序遍历结果如下:\n");
  MidOrder(root);
  printf("\n");
  printf(" 1-----------查找\n");
  printf(" 2-----------查找\n");
  printf(" 3-----------查找\n");
  printf("请选择(1-3):");
  scanf("%d",&k);
  switch(k){
    case 1:
      printf("选择了查找\n");
      printf("请输入要查找的值:");
      scanf("%d",&val);
      if(Search(root,val)!=NULL){
        printf("找到了\n");
      }else{
        printf("没有找到\n");
      }
     break;
    case 2:
      printf("选择了插入\n");
      printf("请输入要插入的值:");
      scanf("%d",&val);
      if(Insert(root,val)!=0){
        printf("插入成功\n");
        printf("对新二叉排序树进行中序遍历的结果如下:\n");
        MidOrder(root);
        printf("\n");
      }else{
        printf("插入失败,值为%d的结点已存在\n",val);
      }
     break;
    case 3:
      printf("选择了删除\n");
      printf("请输入要删除的值:");
      scanf("%d",&val);
      if(Delete(root,val)!=1){
        printf("删除成功\n");
        printf("对新二叉排序树进行中序遍历的结果如下:\n");
        MidOrder(root);
        printf("\n");
      }else{
        printf("删除失败,值为%d的结点不存在\n",val);
      }
     break;
    default:
        printf(" 1-----------查找\n");
        printf(" 2-----------查找\n");
        printf(" 3-----------查找\n");
      break;
  }
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值