查找

查找
一、查找的基本概念
查找表;可以看作一个新的ADT工具类,数据对象是候选记录的集合,核心操作是
查找
静态查找表:一旦创建,主要是查找,很少或者不进行记录的插入和删除
动态查找表:查找的同时会对查找表进行插入、删除
关键字:记录中某个数据项的值,可用来识别一个记录
主关键字:唯一标识数据元素
次关键字;可以标识若干个数据元素


二、静态查找表的查找
定义:
typedef *** KeyType;//关键字类型
typedef struct Search{
      KeyType key;
      ...;
}ElemType;//记录类型
typedef struct {
      ElemType *elem;//数组首地址
      int length;//表长,有效记录
}SSTable;




静态查找表上的顺序查找:


//添加哨兵,从后向前比较,省略每次循环事的越界检查
int Seach_Seq(SSTable ST,KeyType key)
{
      ST.elem[0].key=x;
      for(i=ST.length;St.elem[i].key!=x;--i)
            return i;
}
*记第i个元素被查找的概率为Pi, 顺序查找平均查找长度:ASLSS=n*P1+(n-1)*P2+..+Pi*(n-i+1)+..+1*Pn   +(n+1)*P0
*通常所查找元素均在ST中,此时P0=0
*若查找保证成功且各元素几率同(1/n)则ASLSS=(n+1)/2
*若成功与否各50%,且各元素被找到概率同(1/2n)则
ASLSS=(n+1)/4  +  (n+1)/2=  3*(n+1)/4 
*概率越大越靠后放则ASL越小,事先不知概率可动态调整


折半查找
int Search_Bin(SSTable ST,  
                      KeyType key){
  low=1; high=ST.length; 
  while (low <= high) {
     mid = (low + high) / 2;
     if (key=ST.elem[mid].key)
          return  mid;        
     else if(key<ST.elem[mid].key)
           high=mid-1; 
     else 
           low = mid + 1;
  }
   return 0;
}


折半查找树
*折半查找的判定树:比较时生成根,到左侧区间比较时生成左孩子,右侧比较生成右
孩子,如此递归。
*折半查找判定树任意节点左右子树深度相差最多为1,可证此类树深度为[log2n]+1,
籍此可证查找成功时最坏查找长度为[log2n]+1,借助方形外部结点可证不成功时的
最大查找长度也如此。
*折半查找判定树特点:右子树中各结点值比根大,左子树中各结点值比根小,子树
也如此.根据判定树可如下完成查找:从根结点开始,比当前元素大就向右、小则
向左,或者找到,或者到空. 
*最坏查找长度为[log2n]+1,复杂度O(log2n)
*当判定树为满二叉树时(n=2h-1),若查找成功且各元素几率同(1/n)则ASLbs=(1*20+2*21+3*22+…+h*2h-1)/n≈log2(n+1)-1
对具体例子要会求查找成功和不成功的平均查找长度




分块查找
定义:
对数据进行分块,使得块内无序、块间有序。将各块中的最大关键字构成一个索
引表,表中还要包含每块的起始地址。
过程:
① 对索引表用折半查找定位最后一个小于等于key的块
② 确定了待查关键字所在的块后,块内采用顺序查找
优缺点:
优点:删除或者插入相对容易,移动记录量变小。
缺点:要增加一个索引表的存储空间并对初始索引表进行排序运算。
适用情况:如果线性表既要快速查找又“经常”动态变化,则可采用分块查找。




二叉排序树
定义:
二叉排序树或是空树,或是满足如下性质的二叉树:
 (1)若其左子树非空,则左子树上所有结点的值均小于根结点的值;
 (2)若其右子树非空,则右子树上所有结点的值均大于等于根结点的值;
 (3)其左右子树本身又各是一棵二叉排序树
算法思路:
 p最初指向根结点,只要p不空且p所指结点不是所求则根据比较结果令p变为当前
 结点的左孩子或右孩子。如此重复则最终p空或者找到




typedef struct{     KeyType key;       …;  } ElemType;
typedef struct BiTNode{
    ElemType data;    
    struct BiTNode;   
    *lchild,*rchild;
}BiTNode, *BiTree;
typedef BiTree BSTree; 
typedef BiTNode BSTNode; 
BiTNode *Search(BSTree T, KeyType key){
   BiTNode *p=T;
   while(p!=null&&!EQ(key.p->data.key)){
       if(LT(key.p->data.key))  p=p->lchild;
       else p=p->rchild;
   }
   return p;
}//非递归实现


二叉排序树的操作-递归
*若为空,则返回NULL;
*不空时:
  若查找的关键字等于根结点,返回T
  否则
   若小于根,查其左子树,返回左子树中的查找结果
   若大于根,查其右子树,返回右子树中的查找结果
代码描述:
BSTree SearchBST(BSTree T,KeyType key) {
     if((!T) return NULL;
     else {
         if(key==T->data.key) return T;        
         else if (key<T->data.key)  
             return SearchBST(T->lchild,key);
         else return SearchBST(T->rchild,key);    
      }
} // SearchBST


插入:
若二叉排序树为空,则插入结点应为根结点
否则,在已有二叉排序树中查找是否存在相等结点
若树中已有,不再插入
若树中没有,则查找过程中必然会“落空”。该“落空”的位置就是新结点应该
在的位置
代码描述:
Status InsertBST(BSTree &T, ElemType e)
{
   if((!T){ 
      s=new BiTNode;
      s->data=e; 
      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->lchild,key);
} //考虑非递归如何实现?


创建:
Status CreateBST(BSTree &T){
    T=NULL;
    InputElem(e);   
    while(!IsEnd(e)){ 
        if(InsertBST(T,e)==ERROR)
              return ERROR;
        else InputElem(e);
    }
}


删除:
//首先定位被删除的结点及其双亲
    //如果不存在关键字等于key的结点则直接返回
    //否则,根据被删节点特性分类处理,保证删后仍是二叉排序树
    //若是叶子节点?
    //若只有左孩子?
    //若只有右孩子?
    //若有两个孩子?
void DeleteBST(BiTree &T,KeyType key){
        p=T; f=NULL;
   while(p!=NULL&&!EQ(key,p->data.key)){
       if(LT(key,p->data.key))       {  f=p;  p=p->lchild;  }
       else       {  f=p; p=p->rchild;  }
   }
   if(!p) return;
}
(1)被删除的结点是叶子结点
若有双亲则将双亲结点中相应指针域的值置“空”. 否则,T置空


if( !p->lchild&&!p->rchild ){
   if(!f) { free(p); p=NULL; T=NULL; 
   else if(f->lchild==p){ free(p); f->lchild=NULL; }
   else {free(p); f->rchild=NULL;}
}


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


if(!p->lchild){//左子树为空而只有右子树的情况
   if(!f) {T=p->rchild; free(p);}
   else if(f->lchild==p){f->lchild=p->rchild; free(p);}
   else {f->rchild=p->rchild; free(p);}
}//只有左子树类似处理


(3)被删结点基友左子树也有右子树
找左子树最大元素代替被删除元素,归结为前一情况(还可…)


if(p->lchild&&p->rchild){
   f=p; q=p->lchild;  //f始终指向q的双亲,方便后面的删除
   while(q->rchild){f=q; q=q->rchild;} //q定位最大,f指向其双亲
   p->data=q->data;  //左子树最大者的值填充到原本被删节点
   if(f->lchild==q) f->lchild = q->lchild;  //删除左子树中最大者
   else f->rchild=q->lchild;     
   free(q);
}


代码实现:
void DeleteBST(BiTree &T,KeyType key){
 //首先定位被删结点及其双亲, 不存在则直接返回
 p=T; f=NULL;
 while(p!=NULL&&!EQ(key,p->data.key)){
   if(LT(key,p->data.key)){f=p;p=p->lchild;}else{f=p; p=p->rchild;}
 } 
 if(!p) return;
if(p->lchild&&p->rchild){//若被删节点有两个孩子
   f=p; q=p->lchild;  //f始终指向q的双亲,方便后面的删除
   while(q->rchild){f=q; q=q->rchild;} //q定位最大,f指向其双亲
   p->data=q->data;  //左子树最大者的值填充到原本被删节点
   if(f->lchild==q) f->lchild = q->lchild; else f->rchild=q->lchild;   
   free(q);
}
else if(!p->lchild){//若左孩子为空(包括只有右孩子或两个孩子都没有的情况)
   if(!f) {free(p); T=p->rchild;}
   else if(f->lchild==p){f->lchild=p->rchild; free(p);}
   else {f->rchild=p->rchild; free(p);}
}
else   {…} //只有左孩子,仿照上一段代码, 绿色部分换成p->lchild

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值