数据结构_查找

查找

概述

查找:
——在数据集(表)中找出一个特定元素(的位置)。
这一概念中涉及到以下几个相关的问题:
(1)数据表:什么样数据表?
也就是数据表的组织形式?例如:
汉语字典、英语辞典;
一个城市的电话号码簿。
高考成绩表。
查找表:
——同类型的数据元素(记录)所构成的集合。
顺序表:数据元素构成一个序列。
树表:以树结构的形式组织。
散列表:以某种函数的方式来确定元素的地址,实现数据表的组织。
索引表:为元素建立索引,以提高查找的速度。
显然,查找的方法取决于数据表的组织形式。
例如:在汉语字典和英语辞典中的查找就有明显差异。
因此,需要注意:如何确定查表结构?如何实现对给定数据表的查找?

(2)关于其中的特定元素
如何标识所需要查找的元素?
以高考成绩为例,显然是以准考证号标识的。
更一般地说,涉及到字段
字段:如第一章所述,一个元素通常包括多个字段,
——查找表中的元素也由多个字段(项)组成。
例如,高考成绩信息中,包括姓名、准考证号、各单科成绩和总分等字段。
称其中可以标识元素的字段关键字,分两种情况:
——主关键字:唯一标识一个元素的字段
例如,高考成绩信息中的“准考证号”字段。
次关键字:可能标识到多个元素的字段
例如,高考成绩信息中的“考生姓名”字段,
因为现实中有太多同名同姓的人。

(3)如何查找?
取决于查找表的组织方式。例如:
汉语字典的查找方法;
英语词典的查找方法;
某单位通信录中查找特定单位的方法等。
(4)查找成功和查找失败:
若找到指定的元素,则称为查找成功;否则称为查找失败
(5)如何评价查找方法的性能?
以查找长度来描述
查找长度:
——查找过程中所做的元素或关键字的比较次数。
涉及到:
平均查找长度ASL,
最大查找长度
失败查找长度

顺序表查找

普通查找

问题描述:

  • 查找表以顺序结构来存储,
    典型地是一维数组;也可能是链表,或顺序文件
    本章更多地讨论是面向一维数组
  • 要求在此表中找出关键字的值为x的元素的位置,
    若查找成功,则返回其位置(即下标),
    否则,返回一个表示元素不存在的下标(如0或-1)

按照查找表中数据的特性,以及对应的查找方法,可分为以下几种:

  • 简单顺序查找----没有任何关于数据元素分布的特性
  • 有序表查找------二分查找(折半查找)
  • 索引表查找------数据表分块有序

问题描述:
在数组A[n]中查找元素关键字为x的元素,
若查找成功,则返回元素的下标,否则返回-1。
在这里插入图片描述
从前往后

int  search ( elementtype A[],
                  keytype x) 
{    int i;
    for(i=0;i<n;i++) 
        if (A[i].key==x)  return(i);
    return(-1);
}

从后往前

int  search ( elementtype A[],
                  keytype x) 
{    int i;
    for(i=n-1;i>=0;i--) 
        if (A[i].key==x)  return(i);
    return(-1);
}

在这里插入图片描述

int  search ( elementtype A[],
                  keytype x) 
{    int i;
    A[0].key=x;
    while (A[i].key != x) i--;
    return(i);
}

在这里插入图片描述

  1. 各元素的查找长度:
    1,2,3,…,n (或n-1: 设置监视哨时)
  2. 等概率情况下的平均查找长度:
    ASL=(1+2+……+n)/n=(n+1)/2
  3. 失败查找长度=n+1

二分查找

问题描述:

在递增有序(或递减有序,在此不妨采用递增)数组A[n]中查找元素关键字为x的元素,
若查找成功,则返回元素的下标,否则返回-1。
在这里插入图片描述
在这里插入图片描述
这里选mid-1、mid+1,不仅可以利用已查找的,还可以避免一种特殊情况:刚开始的max就是目标(如果以mid作为分界点会收缩到max-1,碰不到max)
在这里插入图片描述

int bin_search(elementtype A[ ],int n, 
                          keytype x)
 { int mid,low=0,high=n-1;       
                            //初始化查找区域 
  while ( low<=high)
  { mid=(low+high)/2;
     if (x==A[mid].key) return  mid;
     else if (x<A[mid].key) high=mid-1;
                    else low=mid+1;
  }
  return  -1;    //返回查找失败的标志
}

递归写法

int  binsearch(elementtype A[ ],
keytype x,int low,int high)
{
   if(low>high) return -1;
  else
    {  mid=(low+high)/2; 
       if (A[mid].key= =x) return mid;
         else if(x<A[mid].key) return
            binsearch( A[ ],x,low,mid-1); 
         else return
            binsearch( A[ ],x,mid+1,high);
    }
 } 

其他一些结构

在这里插入图片描述
把数据有序地放到二叉树之中,这样查起来也很快。
左下角的两个先不做分析,因为这里只是简单提一下
在这里插入图片描述
块与块之间是有序的,但是块内部是无序的

索引表的查找方法:
分两步进行

  1. 首先要在索引表中查找以确定元素所在的块;
  2. 然后在所确定的块中进行查找。

其中,
块间查找的实现:
在索引表中的查找既可以采用简单顺序查找,
也可以采用二分查找;

块内查找的实现:
只能采用简单顺序查找。
索引表查找的性能分析:
介于简单顺序查找和二分查找之间

二叉排序树

定义:
   二叉排序树是一棵二叉树,或者为空,或者满足以下条件:
  1. 若左子树不空,则左子树中所有结点的值小于根结点的值;
  2. 若右子树不空,则右子树中所有结点的值不小于根结点的值;
  3. 左右子树都为二叉排序树。

在这里插入图片描述

由定义可推出二叉排序树的特点:
按照左、中、右的次序遍历,
所得到的中序序列
是非降序列。
还有一点,从定义可以看出对于一组数据二叉排序树的结构不是唯一的,这就导致了他可能会往一端偏,所以就有了平衡二叉树,B树,红黑树等树去改善这个缺点。

查找

在这里插入图片描述

      bnode *bstsearch(bnode *T,           
                           elementtype x) { 
         p=T;                               
         while ( p != NULL ) {                   
           if ( p -> data = = x )             
              return p;                     
           if ( x < p -> data )               
                   p = p -> lchild;         
           else  p = p -> rchild;           
                                            
        }                                   
        return NULL;                           
    }                                       

递归写法

bnode *bstsearch(bnode *T,
                          elementtype x) {     
       if ( T == NULL )    return T;                                  
       if (T -> data == x )  return T;                      
       if (x < T -> data)                         
          return bstsearch(T->lchild,x);           
       else 
          return bstsearch(T->rchild,x); 
}                                   

二叉排序树的构造:

从空树出发,依次插入各结点(作为叶子结点)。
二叉排序树中插入结点:
(1)若结点的值小于根结点的值,
则往左子树中插入
----通过递归调用插入算法来实现。
(2)若结点的值大于等于根结点的值,
则往右子树中插入(递归调用)。
按此方式递归调用若干次后,
可以搜索到一个空子树位置,即要插入的位置。
在这里插入图片描述

        void insert(bnode *& T, bnode *s)//此函数只用于插入一个结点s
                 //  将s所指结点插入到以T为根指针的二叉排序树中
         {     if ( T = = NULL )        // T 为空时
                      T = = s;                  // 新结点作为根结点
                else    if ( s->data < T->data ) 
                                 insert( T -> lchild, s );
                          else insert( T -> rchild, s );
        }         

二叉排序树的构造算法
void  creat(bnode *&T) 
         // 接受读入数据,从空树开始构造二叉排序树
{            T= =NULL;
              cin>>x;
              while (x!=结束符)
              {
                  s=new bnode;    s -> data=x; 
                  s -> lchild=NULL;  s -> rchild=NULL;
                  insert(T,s);
                  cin>>x;
              }
       }

在这里插入图片描述

平衡二叉树AVL

在这里插入图片描述

定义

平衡二叉树是一棵二叉排序树,或者为空,
或者满足以下条件:
1. 左右子树高度差的绝对值不大于1;
2. 左右子树都是平衡二叉树。
在这里插入图片描述
在这里插入图片描述
LL:
在这里插入图片描述
LR:
在这里插入图片描述

RL:
在这里插入图片描述
RR:
在这里插入图片描述
可以看出两两对称,还有为什么要是关注结点及其左右孩子,因为第一次出现不平横,只要他们的位置搞一下就能消去这个不平衡。
看个例题:
在这里插入图片描述
每加一个结点就不断往上走,遇到不平衡的结点就调整(由于是在构造的时候,所以一次就可以解决,不用再往上走了)
在这里插入图片描述

习题

在这里插入图片描述
第一题:先弄三个,搞掉一个调整方法,再看那个调整好的树的结构,选择一个合适的第四个数,又可以搞掉一个调整方法。继续这样的过程,直到凑够四个方法。
第二题:在这里插入图片描述
第三题:
f(1)=1,f(2)=2;f(n)=f(n-1)+f(n-2)+1//f(k)表示k层最小平衡二叉树的结点数,解释一下f(n-1)+f(n-2)+1,加一很好理解,f(n-1)也很好理解因为f(n)要有n层,为什么选f(n-2),因为f(x)递增,平衡二叉树要求平衡因子绝对值不超过1,所以只能选f(n-2)
第四题:可以
如图在这里插入图片描述

B树

定义:m阶B-树(m≥3)满足如下条件:
1) 每一个结点分支数≤m;
2) 根结点分支数≥2(要求此根结点不为叶子结点);
3) 其余分支结点的分支数≥ m/2 (向上取整) ;
4) 所有叶子结点在同一层;
5) 每一个结点的结构如下:
在这里插入图片描述
在这里插入图片描述
看个例子好懂一点
在这里插入图片描述
重点分析这个结点
在这里插入图片描述
上图有无,限定为[2,3]我看错了是向上取整。

插入

在这里插入图片描述
在这里插入图片描述
过程是这样的,先找到那个数插到哪个叶子里,如果分支数超出了限定就拿出一个(一般选择中间因为这样能增加容纳能力)放到上一层,如果上一层也超了,就继续往上走,直到不超。

删除

在这里插入图片描述
在这里插入图片描述
这里找了两次前驱
在这里插入图片描述
找了两次后继

散列表查找

引入

在这里插入图片描述

定义

对给定的关键字key,
用一个函数H(key)计算出元素地址,
由此而得散列表(Hash表,哈希表),
其中函数H(key)称为散列函数
此函数值称为散列地址。
然而,在实际应用中,会出现这样的情况:
k1≠k2,但H(k1)=H(k2) ,
称这种现象为冲突现象,k1,k2为同义词。
针对冲突——如何解决冲突呢?

找散列函数

在这里插入图片描述
各种奇怪的方法,反正目标只有一个,给元素整一个值,尽量减少冲突。
在这里插入图片描述
冲突了的话,我们就调用解决冲突的方法继续找位置,直到找到一个空位置,然后查找的话也想这样走一遍直到找到该元素。
在这里插入图片描述
ASL=每个元素查找时调用函数次数/元素总数。
在这里插入图片描述
冲突了就接在后面

查找

在散列表中查找元素的过程和构造的过程基本一致:
对给定关键字k,由散列函数H计算出该元素的地址H(k)。
若表中该位置为空,则查找失败。
否则,比较关键字,若相等,查找成功,否则根据构造表时所采用的处理方法找下一个地址,直至找到关键字等于k的元素(成功)或者找到空位置(失败)为止。

一般在用链地址法构造的表中进行查找,比在用线性探测法构造的表中进行查找,查找长度要小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值