顺序查找、折半查找、分块查找

目录

一、查找的基本概念

二、顺序查找

一般线性表的顺序查找

 有序线性表的顺序查找

三、折半查找

折半查找的算法

判定树 

四、分块查找


一、查找的基本概念

  • 查找:在数据集合中寻找满足某种条件的数据元素的过程称为查找。查找的结果一般分为两种:一是查找成功,即在数据集合中找到满足条件的数据元素;二是查找失败
  • 查找表(查找结构):用于查找的由同一类型的数据元素(或记录)构成的集合查找表本质是表中记录之间仅存在"同属一个集合”这个逻辑的集合结构。为此,我们在数据元素之间人为地加上一些关系,以便按照某种规则查找,即用另一种数据结构来表示查找表
  • 对查找表进行的操作一般有四种:①查询某个特定的数据元素是否在查找表中;②检索满足条件的某个特定的数据元素的各自属性; ③在查找表中插入一个数据元素;④在查找表中删除某个数据元素。只作前两种查找操作的查找表为静态查找表可以作上述四种操作,即在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素的为动态查找表
  • 关键字:数据元素中可以标识元素的某个数据项的值主关键字可以唯一标识一个记录,次关键字可以识别若干记录。使用基于主关键字的查找,查找结果应该是唯一的。
  • 平均查找长度为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值:
  •  ASL=\sum_{i=1}^{n}p_{i }C_{i}   
  • (Average Search Length),p_{i }为表中第i个元素被查找的概率,C_{i}是将它查找成功所用的比较次数。一般认为每个数据元素的查找概率相等,即p_{i } = 1 / n 。ASL是评价查找算法好坏的重要指标。一般查找成功的可能性比查找不成功的可能性要高地多,但当查找不成功的情形不能忽视时,查找算法的平均查找长度为查找成功时的平均查找长度和查找不成功时的平均查找长度之和。

二、顺序查找

顺序查找又称线性查找,它对于查找表以链表或数组存储都是适用的。顾名思义,沿着表中的顺序关系扫描每个元素。通常分为对无序线性表的顺序查找和对按关键字有序的线性表的顺序查找。 

一般线性表的顺序查找

其基本思想是从线性表的一端开始,逐个比较检查关键字是否满足条件。若查找到满足条件的记录则查找成功,若按顺序查找完整个表还未查找成功则查找失败。下面给出算法代码:

typedef struct{
    ElemType *elmem;//存储表中记录的数组的基址,0号位置留空
    int TableLen;//查找表表长
}SSTable;//查找表的数据结构
int Serach_Seq(SSTable ST, ElemType key)
{
    ST.elem[0]=key;//哨兵位置为待查找关键字大小
    for(int i=ST.TableLen; ST.elem[i]!=key;i--);
    //从数组尾部往前查找,直到找到符合条件的记录
    return i;//返回查找到元素的下标,若返回0代表查找失败    
}

哨兵位的作用是为了在for循环判断跳出条件时不必比较下标 i 是否越界,提高程序的效率。在直接插入排序中也可以用到哨兵位。

查找表中一共n个元素,对于上述算法查找第 个记录,我们需要比较n-i+1次,假设每个记录被查找的概率相同:

查找成功时的ASL=\sum_{i=1}^{n}P_{i}(n-i+1)=\frac{1}{n}\frac{n(n+1)}{2}=\frac{n+1}{2}

查找失败时的ASL=n+1(使用哨兵位时除了跟表中每个记录比较之外还和哨兵位比较,不使用哨兵位时也要多比较一次判断越界)

对于每个记录被查找概率并不相等的情况,我们令表中记录按查找概率重新排列,使得查找概率较大的记录被查找所比较的次数较小,能够减小平均查找长度。

 有序线性表的顺序查找

如果查找表中的记录按关键字大小有序排列时,我们在循环比较时如果发现查找表中剩下的未比较记录已经不可能查找成功时,应直接退出查找,即查找失败。下面给出算法代码:

typedef struct{
    ElemType *elmem;//存储表中记录的数组的基址,0号位置留空
    int TableLen;//查找表表长
}SSTable;//查找表的数据结构
int Serach_Seq(SSTable ST, ElemType key)
{//有序表中记录大小是从小到大排序的
    ST.elem[0]=key;//哨兵位置为待查找关键字大小
    for(int i=ST.TableLen; ST.elem[i]>key;i--);
    //从数组尾部往前查找,当查找到不比key大的记录时退出
    if(ST.elem[i]<key) return 0;
    //判断是找到了退出循环还是再也找不到了退出循环
    return i;//返回查找到元素的下标,若返回0代表查找失败   
}

对于查找成功时的平均查找长度和一般线性表的顺序查找并无不同。

对于查找失败时的平均查找长度有了较大改进,我们按退出循环时已经比较关键字的次数能够划分出n+1个区间,打个比方,假设查找表为{10,20}则我们的失败区间为(- ∞,10)(10,20)(20,∞)这三个区间,可以看到第一个区间的比较次数为1,第2个第3个都为n次,推广到一般情况:        ASL=\sum_{i=1}^{n}P_{i}C_{i }=\frac{1+2+...+n+n}{n+1}=\frac{n}{2}+\frac{n}{n+1}

其中我们假设每个失败区间中关键字被查找的概率相等。

三、折半查找

折半查找:又称二分查找,它仅适用于有序的顺序表。 

折半查找的算法

算法思想:首先将给定值key与有序表中间位置记录比较,若相等则查找成功;若不相等,我们只需查找中间元素前半部分的记录或者后半部分的记录即可。如此重复,直到查找成功,或确定表中没有所需查找的记录,则查找不成功。算法如下:

int Serach_Binary(SeqList L, ElemType key)
{//有序表中记录大小是从小到大排序的
   int low=0,high=L.TablenLen-1,mid;
    while(low<=high)
    {
        mid=(high+low)/2;//取中间位置
        if(L.elem[mid]==key)
        return mid;//查找成功
        else if((L.elem[mid]<key)
        low=mid+1;//从后半部分继续查找
        else high=mid-1;//从前半部分继续查找
    }
    return -1;//返回-1代表查找失败   
}

因为折半查找需要方便地定位查找区域,所以它要求线性表有随机存储的特性,因此,该方法不适合于链式存储结构。

判定树 

折半查找的过程可以用下图所示的二叉树来描述,称为判定树树中非终端结点都是代表能查找成功的记录,树中叶子结点代表查找不成功的情况。它满足下列条件:

1.查找成功时的比较次数为从该结点到根结点的路径长度与该结点进行的一次比较之和。

2.查找失败时的比较次数为从该结点到根结点的路径长度。

3.若有序序列有n个元素,对应有n个非终端结点和n+1个叶子结点。

4.每个结点的值都大于其左孩子结点的值,小于其右孩子结点的值。

上图这个判定树找中间值的操作是 (low+high)/2,它在有偶数个记录时中间值会落到靠左的位置。所以上图我们在{7,10}中选择了7,并且10成为了7的右孩子结点。

事实上我们可以这样取中间值⌈(low+high)/2⌉,符号内为浮点数,这样它在有偶数个记录时中间值会落到靠右位置,此时判定树如下图:

 因此,得到规律:

  1. 若mid=⌈(low+high)/2⌉时,对于任意一个结点,必有左子树结点数-右子树结点数=0或1.
  2. 若mid=⌊(low+high)/2⌋时,对于任意一个结点,必有右子树结点数-左子树结点数=0或1.
  3. 对于给定有序表,其判定树的树形只有两种情况(代码不同),当代码明确时,二分查找的判定树唯一。

 用折半查找法查找给定值的比较次数最多为不会超过该二叉树的高度⌊ logn⌋+1(⌊ logn⌋表示不大于X的最大整数)(比较次数为高度是说明非终端结点在最后一层)

当n=2^h-1时,即满二叉树时,查找成功时折半查找的平均查找长度如下:

折半查找的时间复杂度为O(log​n),平均情况下比顺序查找效率高。

四、分块查找

分块查找又称索引顺序查找它吸取了顺序查找和折半查找各自的优点,既有动态结构,又适合快速查找。 

分块查找的基本思想将查找表分为若干块,块长不定,块内可以是无序的,但是块之间是有序的,即前一个块中的最大关键字小于后一个块中的最小关键字。为此我们建立一个索引表包含如下所示信息:

最大关键字224886
起始地址1713

 分块(索引顺序)查找的过程:

  1. 在索引表中确定待查记录所在的块,可以按顺序查找或折半查找索引表
  2. 在块内顺序查找。

分块查找平均查找长度为索引查找和块内查找的平均查找长度之和:

将长度为n的查找表均匀地分为b块,每块有s个记录,在等概率情况下,

对索引表采用顺序查找,则平均查找长度为

ASL=L_{I}+L_{S}=\frac{b+1}{2}+\frac{s+1}{2}=\frac{s^2+2s+n}{2s},        当s=\sqrt{n}时,ASL(min)=\sqrt{n}+1

对索引表采用折半查找,则平均查找长度为

ASL=L_{I}+L_{S}=⌈\log_{2}(b+1)⌉+\frac{s+1}{2}

  • 6
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晴落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值