基于树的查找法

二叉排序树:

二叉排序树(二叉查找树)是一种特殊结构的二叉树,其定义为:
是一棵空树,或者是具有如下性质的二叉树:
1)若左子树非空,则左子树上所有结点的值均小于根结点的值;
2)若右子树非空,则右子树上所有结点的值均大于根结点的值;
3)它的左右子树也分别为二叉排序树。
在这里插入图片描述
重要性质中序遍历一个二叉排序树时可以得到一个递增有序序列。

结构定义:

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

二叉排序树的插入与创建

二叉排序树的插入:
已知一个关键字值为Key的结点s,插入的方法:
①若二叉排序树是空树,则Key 成为二叉排序树的根;
②若二叉树排序树非空,则将key与二叉树排序树的根进行比较:

  1. 如果key的值等于根结点的值,则停止插入;
  2. 如果key的值小于根结点的值,则将key插入左子树;
  3. 如果key的值大于根结点的值,则将key插入右子树。
void InsertBST(BSTree *bst, KeyType key) 
/*若在二叉排序树中不存在关键字等于key的元素,插入该元素*/
{  BiTree s;
   if (*bst == NULL) 
    {/*递归结束条件*/
	    s = (BSTree)malloc(sizeof(BSTNode));/*申请新的结点s*/
       	s-> key = key; 
       	s->lchild = NULL;  
       	s->rchild = NULL; 
       	*bst = s; 
    } 
    else if(key < (*bst)->key)
        InsertBST(&((*bst)->lchild), key);/*将s插入左子树*/
    else if (key > (*bst)->key)  
        InsertBST(&((*bst)->rchild), key); /*将s插入右子树*/
}

插入结点作为叶结点,不涉及结点移动.

创建二叉排序树:
将二叉排序树初始化为一棵空树,然后逐个读入元素:
① 每读入一个元素,就建立一个新的结点插入到当前已生成的二叉排序树中;
② 调用上述二叉排序树的插入算法将新结点插入。

void  CreateBST(BSTree  *bst) 
/*从键盘输入元素的值,创建二叉排序树*/
{    KeyType key;
    *bst = NULL;
     scanf("%d", &key);
     while(key != ENDKEY)   /*ENDKEY为自定义常数*/
      {
	     InsertBST(bst, key);
      	 scanf("%d", &key);
      }
} 

设关键字的输入顺序为:45,24,53,12,28,90,按上述算法生成的二叉排序树的过程:

在这里插入图片描述

同样的元素序列,如果输入顺序不同,则所建的二叉树形态也不同。

二叉排序树的查找

与折半查找类似,首先将待查关键字k与根结点关键字t进行比较,如果:
1)k = t:则返回根结点地址;
2)k < t:则进一步查左子树;
3)k > t:则进一步查右子树。

递归算法

BSTree  SearchBST(BSTree bst, KeyType key)
/*在二叉排序树中递归查找关键字为key的元素*/
{    if(!bst) return NULL;
     else if(bst->key == key)
        return bst;/*查找成功*/
     else if (key < bst-> key)
    	return SearchBST(bst->lchild, key);/*在左子树继续查找*/
     else 
     	return SearchBST(bst->rchild, key);/*在右子树继续查找*/
} 

非递归算法

BSTree SearchBST(BSTree bst, KeyType key) 
{   BSTree q = bst;
    while(q)
    {   if (q->key == k)  return q;/*查找成功*/
    	if (key < q->key)  q = q->lchild;/*在左子树中查找*/
     	else q = q->rchild; /*在右子树中查找*/
  	}
return NULL;/*查找失败*/
}/*SearchBST*/ 

二叉排序树的删除

必须保证删除后所得的二叉树仍然满足二叉排序树的性质(排序)不变。

删除操作:

① 首先确定被删除的结点是否在二叉排序树中。若不在,则不做任何操作;
② 否则,假设要删除的结点为p,结点p的父结点为f,并假设结点p是其父f的左孩子(右孩子的情况类似)。

在这里插入图片描述
下面分三种情况讨论:
1)若p为叶结点,则可直接将其删除:
f->lchild = NULL;free(p)
2)若p结点只有一孩(只有左子树或右子树),则接班
将p左子树或右子树直接改为其父f的左子树
f->lchild=p->lchild(或f->lchild=p->rchild);free(p)
3)若p既有左子树,又有右子树, 则处理的方法有两种:

  1. 找到p结点在中序序列中的直接前驱s结点,
    将p左子树改为f左子树,右子树改为s的右子树:
    在这里插入图片描述

  2. 找到p结点在中序序列中的直接前驱s结点,
    然后用s结点的值,替代p结点的值,再将s结点删除,
    原s结点的左子树改为s的父结点q的右子树:
    在这里插入图片描述
    两个父子追针用法s:p左孩的右孩的右孩…

删除结点的算法(方法2):

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;	/*找不到,返回原树*/
        if(p->lchild == NULL)	/*p无左子树*/
         { if(f == NULL) t = p->rchild;	/*p是根,右孩继位成根*/
 	       else if(f->lchild == p)		/*p是f的左孩子*/
     		  f->lchild = p->rchild; /*右子树链到f的左链上*/
           else 
              f->rchild = p->rchild;	/*p右孩接班到f右链*/
          free(p);/*释放被删除的节点p*/
         }
    else /*p有左子树*/
    { 	q = p; s = p->lchild;
     	while(s->rchild)/*p左子树的最右下结点*/
     	{	q = s; s = s->rchild; }
  	        if(q == p)   q->lchild = s->lchild; /*没进while,s是p的左孩,s直接接班,左子树链到q上*/
  	        else  q->rchild = s->lchild;//托付左孩去接班
  	        p->key=s->key;/*将s的值赋给p*/
 	        free(s);
 	    }
   return t;
} 

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

同样关键字序列的一组结点,结点插入的次序不同,构成的二叉排序树的形态和深度不同——先到为根
二叉排序树的平均查找长度ASL与树的形态有关
各分支越均衡,树的深度浅,其平均查找长度ASL越小。
在这里插入图片描述
ASL(a) = (1+2+2+3+3+3)/6=14/6;
ASL(b) = (1+2+3+4+5+6)/6=21/6.

若考虑把n个结点,按各种可能的次序插入到二叉排序树中,则有n!颗二叉排序树(其中有的形态相同)。
可以证明,对这些二叉排序树进行平均,得到的平均查找长度仍然是O(log2n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值