第十一章 执行查询算法
基本概念:
三类查找方法:线性查找、树形查找、哈希表查找
动态查找表:在查找的同时,对表做修改操作(如插入和删除),则相应的表称为动态查找表
静态查找表:与动态查找表相反
查找过程中对关键字需要执行的平均比较次数(也称平均比较长度作为衡量一个查找算法优劣的标准
平均比较长度:
其中:n是结点的个数;pi是查找第i个结点的概率。若不特别申明,认为每个结点的查找概率相等,都为1/n;ci是找到第i个结点所需进行的比较次数。
线性查找:
基本思想:从表的一端开始,顺序扫描线性表,依次将扫描的结点关键字和给定K值相比较。若当前扫描到的结点关键字与K相等,则查找成功;若扫描结束,仍未找到关键字等于K的结点,则查找失败。
算法的平均查找长度为:n
在下列两种情况下,只能采用顺序查找:
1) 如果顺序表为无序表,则只能用顺序查找
2) 采用链式存储结构的线性表,只能采用顺序查找
二分查找
二分查找又称折半查找,它是一种效率较高的查找方法。二分查找要求线性表示有序表,即表中结点按关键字有序,并且要用顺序表作为表的存储结构。
基本思想:设置三个变量low,high和mid,它们分别指向表的当前指向表的当前待查找范围的下界,上界和中间位置。初始时,low=0;high=n-1,设待查找数据元素的关键字为Key;
1) 令mid=(low+high)/2
2) 比较Key与R[mid]的Key值的大小,若:
R[mid]的Key值等于Key则查找成功,结束查找
R[mid]的Key值小于Key,表明关键字为Key的记录可能位于记录R[mid]的右边,修改查找范围,令下界指示变量low=mid+1,上界指示变量hight保持不变
R[mid]的Key值大于Key,表明关键字为Key的记录可能位于记录R[mid]的左边,修改查找范围,令下界指示变量high=mid-1,下界指示变量low保持不变
比较当前变量low与high的值,若low≤high,重复(1)、(2),若low>high,表明整个查找完毕,线性表中不存在关键字为Key的记录,查找失败。
平均查找长度:ASL=log2(n+1)-1
分块查找:
分块查找又称为顺序查找。它是一种性能介于顺序查找和二分查找之间的查找方法。
基本思想:分块查找要求把顺序表分成若干块,每一块的键值存储顺序是任意的,但要求“分块有序”,前一块中的最大键值小于后一块中的键值。即块间结点有序,块内结点任意。另外,还需要简历一个索引表,索引表中的每一项对应顺序表的一块,索引项由关键字域好链域组成,关键字域存放对应块内结点的最大值,链域存放对应块首结点的位置。索引表中的索引项是按键值递增顺序存放。
抽取各块中的最大关键字及其起始位置构成一个索引表,索引表按关键字有序,所以索引表是一个递增有序集。
在带索引表的顺序表中查找关键字等于Key的记录时,需要分两步进行
1) 首先查找索引表,确定待查记录所在块。索引表示有序表,可以此采用二分查找或顺序查找,以确定待查找的结点在哪一块。
2) 在已确定的块中进行顺序查找。当块内的记录是任意排列的,只能用顺序查找。
平均查找长度:ASL=,分块查找是一种介于顺序查找和二分查找之间的查找方法,它的速度要比顺序查找速度快,但付出的代价增加辅助存储空间和将顺序表分块排序;同时它的速度要比二分查找法速度慢,但好处是不需要对全部记录进行排序。
哈希查询技术
基本原理:将给定的键值转换为偏移地址来检索记录
键转换为地址是通过一种关系(公式)来完成的,这就是哈希(散列)函数。哈希函数对键执行操作,从而给定一个哈希值,该值是代表可以找到该记录的位置。
哈希法的基本思想是:设置一个长度为m的表T,用一个函数将数据集合中n个记录的关键字尽可能唯一地转换成0~m-1范围内的数值。
哈希表的冲突现象:两个不同的关键字,由于哈希函数值相同,因而被映射到同一表位置上。该现象称为冲突或碰撞。发生冲突的两个关键字称为该哈希函数的同义词。
构造哈希函数和简历解决冲突的方法是建立哈希表的两大任务。
好的哈希函数选择有两条标准:
1) 简单并且能够快速计算
2) 能够在址空间中获取键的均匀分布
几种常用的构造哈希函数的方法:
平均取中法:具体的做法是先通过关键字的平方值扩大相近数的差别,然后根据表的长度取中间的几位数作为哈希的函数值。又因为一个乘积的中间几位和乘数的每一位都相关,所以由此产生的散列地址较为均匀。
除余法:以表长m来除关键字,取其余数作为散列地址。
折叠移位法:根据哈希表长将关键字尽可能分成若干段,然后将这几段的值相加,并将最高位的进位舍去,所得结果即为其哈希地址。相加有两种方法,一种是顺折,即把每段中的各位值对齐相加,称之为移位法;另一种对折,像纸条一样,把原来关键字按照划分的中界向中间折叠,然后求和,称之为折叠法。
解决哈希冲突
开放定址法:当冲突发生时,按照某种方法探测表中的其他存储单元,直到找到空位置为止。下面介绍几种
1) 线性探测法:将散列表T[0…m]看成是一个循环向量,若初始探测的地址为d(h(key)=d),则最长的探测序列为:
d,d+1,d+2,…,m-1,0,1,…,d-1
即:探测时从地址d开始,首先探测T[d],然后依次探测T[d+1]…直到,T[m-1],此后又循环到T[0],T[1],…,直到T[d-1]为止。
探测过程终止于三种情况:
若当前探查的单元为空,则表示查找失败(若是插入则将Key写入其中)
若当前探查的单元中还有Key,则查找成功,但对于插入意味着失败
若探测到T[d-1]是仍未发现空单元也未找到key,则无论是查找还是插入均意味着失败(此时表满)
2) 二次探查法:二次探查法的探查序列为:
hi=(h(key)+i*i)%m 0≤i≤m-1
即探查序列为d=h(key),d+12,d+22,…等。
该方法的缺陷是不易探查到整个散列空间。
3) 双重哈希法
该方法是开放定址法中最好的方法之一。在该方法中,一旦发生冲突,会应用第二个哈希函数以获取备用位置。第一次试探有冲突的键很可能在第二个哈希函数结果中有不同的值。
.链表法:链表法解决冲突中的做法是:将所有关键字为同义词的结点连接在同一个单链表中,若选定的哈希表长度为m,则可将哈希表定义为一个由m个头指针组成的指针数组T[0…m-1]。凡是散列地址为i的结点均插入到以T[i]为头指针的单链表中。T中各分量的初值均为空指针。在链表法中,装填因子α可以大于1,但一般取α≤1