查找-二叉排序树

动态查找表:表结构本身是在查找过程中动态生成的,即对于给定值key,若表中存在其关键值等于key的记录,则查找成功返回,否则插入关键字等于key的记录。

二叉排序树或者是一颗空树,或者是具有下列性质的二叉树:

1、若他的左子树不为空,则左子树上所有结点的值均小于它的根结点的值。

2、若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

3、它的左右子树也分别为二叉排序树。

二叉排序树又称二叉查找树,根据上述定义的结构特点可见,它的查找过程与次优二叉树类似,即当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,否则将根据给定值和根结点的关键字之间的大小关系,分别在左子树或右子树上继续进行查找。通常,可取二叉链表作为二叉排序树的存储结构。

首先是辅助宏的定义:

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
#define UNDERFLOW -2
#define NULL 0
#define LH 1 //左高
#define EH 0  //等高
#define RH -1 //右高
typedef int Status;
typedef int KeyType;
typedef char* InfoType;

二叉排序树的存储结构定义:

//二叉排序树的存储结构定义
typedef struct{
   KeyType key;
   InfoType otherinfo; //附加信息
}ElemType;
typedef struct BiTNode{ 
   ElemType data;
   struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
typedef BiTNode BSTNode;
typedef BiTree BSTree; 

查找(递归实现):

算法思想:

若为空,返回NULL。

不空时,

若查找的关键字等于跟结点,返回T;

否则

    若小于根,查其左子树,返回查找结果;

    若大于根,查其右子树,返回查找结果;

BSTree SearchBST(BSTree T,KeyType key){
   /*查找(递归实现)
   若为空 返回NULL 不空时,若查找的关键字等于根结点
   返回T 否则若小于根 查其左子树 返回查找结果 若大
   于根 查其右子树 返回查找结果*/
   if(!T)
       return NULL;
   else if(T->data.key==key)   //在左子树继续查找
       return T; 
   else if(T->data.key<key)    //在右子树继续查找
       return SearchBST(T->rchild,key);
   else
       return SearchBST(T->lchild,key);
}

查找(非递归实现):

p最初指向根结点,只要p不空且p所指结点不是所求则根据比较结果令p变为当前结点的左孩子或右孩子。

如此重复直到p空或者找到。

BSTNode *Search(BSTree T,KeyType key){
    /*查找(非递归实现)
    p指向根结点 只要p不空且p所指结点不是所求则根据比较
    结果令 p变为 当前结点的左孩子 或右孩子。如此重复则
    最终p空或者找到*/
    BSTNode *p=T;
    while(p!=NULL&&p->data.key!=key){
        if(key<p->data.key)
	     p=p->lchild;
       else
            p=p->rchild;
    }
    return p;
}

判断一颗给定二叉树是否是二叉排序树。

运用递归的思想,空树是二叉排序树;当树不空时,先判断左右子树是否是二叉排序树,只要有一个不是则原树不是二叉排序树,如果左右子树都是二叉排序树,看看左子树中最大的是否比根结点小,右子树中最小的是否比根结点大即可。

Status IsBST(BSTree &T)
{
   //判断T是否为二叉排序树
   BSTNode *p;
   if(!T)
       return TRUE;
   else
   {
       if(!IsBST(T->lchild))
           return FALSE;
       if(!IsBST(T->rchild))
	   return FALSE;
       if(T->lchild)
       {
	   //找左子树中最大的与根进行比较
	   p=T->lchild;
	   while(p&&p->rchild)
	       p=p->rchild;
	   if(p->data.key>T->data.key)
	       return FALSE;
       }
       if(T->rchild)
       {
	   //找右子树中最大的与根进行比较
	  p=T->rchild;
	  while(p&&p->lchild)
	      p=p->lchild;
	  if(p->data.key<T->data.key)
	      return FALSE;
       }
       return TRUE;
   }
}

二叉排序树的插入.

若二叉排序树为空,则插入结点应为根结点。

否则,在已有二叉排序树中查找是否存在相等结点。

若树中已有,不再插入。

若树中没有,则查找过程中必然会落空,该落空的位置就是新结点应该在的位置。

插入的过程与查找基本类似。新插入的结点一定在叶结点上。

Status InsertBST(BSTree &T,KeyType key)
{
    /*二叉排序树的插入
    若二叉排序树为空 则插入结点为根结点
    否则 在已有二叉排序树中查找是否存在相等结点
    若树中已有 不在插入
    若树中没有 则查找过程中必然会落空 该落空的位
    置就是新结点应该在的位置*/
    if(!T)
    {
        BSTNode *s;
	if(!(s=(BSTNode *)malloc(sizeof(BSTNode))))
           exit(OVERFLOW);
	s->data.key=key;
	s->lchild=s->rchild=NULL;
	T=s;
	return OK;
   }
   else if(key==T->data.key)
       return ERROR;
   else if(key<T->data.key)
       return InsertBST(T->lchild,key);
   else
       return InsertBST(T->rchild,key);
}

二叉排序树的创建:

从空树出发,依次按照结点插入方法插入各结点。

Status CreateBST(BSTree &T)
{  
    //二叉排序树的创建
    //从空树出发,依次按照结点插入方法插入各结点即可
    T=NULL;
    KeyType key;
    scanf("%d",&key);
    while(key)
    {
       if(InsertBST(T,key))
           scanf("%d",&key);
       else
	   return ERROR;
    }
    return OK;
}

二叉排序树的删除:

首先定位被删除的结点及其双亲,如果不存在关键字等于key的结点,则直接返回。

否则,根据被删结点特性分类处理,保证删除后仍是二叉排序树。

1、被删除的结点是叶子结点。若有双亲则将双亲结点中相应指针域的值置空,否则T置空。

2、被删结点只有左子树或右子树。双亲结点相应指针指向被删结点的唯一子树。

3、被删结点既有左子树也有右子树。找左子树最大的元素代替被删除元素,归结为前一情况。

void DeleteBFT(BSTree &T,KeyType key)
{
   /*二叉排序树的删除
   首先定位被删除的结点及其双亲
   如果不存在关键字等于key的结点则直接返回
   否则 根据被删除结点特性分类处理 保证删后
   仍是二叉排序树 
   被删除的是叶子结点 若有双亲 则将双亲结点中相
   应指针域的值置空 否则T置空
   被删的结点只有左子树或右子树 双亲结点相应指针
   域指向被删结点的唯一子树
   被删结点既有左子树也有右子树 找左子树中最大的
   代替删除元素
   */
   BSTNode *p=T,*f=NULL,*q;
   while(p&&p->data.key!=key)
   {
       if(key<p->data.key)
       {
           f=p;
	   p=p->lchild;
       } 
       else
       {
	   f=p;
           p=p->rchild;
       }
   }
   if(!p)
       return;
   if(!p->lchild&&!p->rchild)
   {
       if(!f)
       {
           free(p);
	   T=NULL;
           p=NULL;
       }
       else if(f->lchild==p)
	   f->lchild=NULL;
       else
	   f->rchild=NULL;
       free(p);
       p=NULL;
   }
   else if(!p->lchild)
   {
       if(!f)
           T=p->rchild;
       else if(f->lchild==p)
           f->lchild=p->rchild;
       else
           f->rchild=p->rchild;
       free(p);
       p=NULL;
   }
   else if(!p->rchild)
   {
       if(!f)
           T=p->lchild;
       else if(f->lchild==p)
           f->lchild=p->lchild;
       else
           f->rchild=p->lchild;
       free(p);
       p=NULL;
   }
   else
   {
       f=p;  //f始终指向q的双亲 方便后面的删除
       q=p->lchild; 
       while(q->rchild)  //q定位最大 f指向其双亲
       {
          f=q;
	  q=q->rchild;
       }
       p->data.key=q->data.key; //左子树最大者的值填充到原本被删结点
       if(f->lchild==q) //删除左子树中最大者
           f->lchild=q->lchild;
       else
           f->rchild=q->lchild;
       free(q);
       q=NULL;
    }
}

二叉排序树查找的性能分析:

平均查找长度和二叉树的形态有关,即,

最好 logN。形态均匀,与二分查找的判定树相似。

最坏:(n+1)/2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值