若哈希地址是两位,则可取这四位中的任意两位组合成哈希地址,也可以取其中两位与其它两位叠加求和后,取低两位作哈希地址7/25/202447五、平方取中法五、平方取中法 对关键码平方后,按哈希表大小,取中间的若干位作为哈希地址六、折叠法六、折叠法(Folding)(Folding) 此方法将关键码自左到右分成位数相等的几部分,最后一部分位数可以短些,然后将这几部分叠加求和,并按哈希表表长,取后几位作为哈希地址这种方法称为折叠法 有两种叠加方法: 1. 移 位 法 ── 将各部分的最后一位对齐相加 2. 间界叠加法 ── 从一端向另一端沿各部分分界来回折叠后,最后一位对齐相加7/25/202448【【例例9.119.11】】关键码为 key=05326248725,设哈希表长为三位数,则可对关键码每三位一部分来分割 关键码分割为如下四组: 253 463 587 05用上述方法计算哈希地址253463587++ 051308Hash(key)=308移位法移位法253364587++ 501254Hash(key)=254间界叠加法间界叠加法 对于位数很多的关键码,且每一位上符号分布较均匀时,可采用此方法求得哈希地址 。
7/25/2024499.4.3 处理冲突的方法处理冲突的方法 一一. 开放定址法开放定址法 所谓开放定址法,即是由关键码得到的哈希地址一旦产生了冲突,也就是说,该地址已经存放了数据元素,就去寻找下一个空的哈希地址,只要哈希表足够大,空的哈希地址总能找到,并将数据元素存入 找空哈希地址方法很多,下面介绍三种: 1. 线性探性探测法法 Hi=(Hash(key)+di) mod m ( 1≤i < m ) 其中: Hash(key)为哈希函数 m为哈希表长度 di 为增量序列 1,2,……,m-1,且di=i7/25/202450【【例例9.129.12】】关键码集为 {47,7,29,11,16,92,22,8,3},哈希表表长为11, Hash(key)=key mod 11,用线性探测法处理冲突,建表如下: 01234567891011224792163729847、7、11、16、92均是由哈希函数得到的没有冲突的哈希地址而直接存入的; Hash(29)=7,哈希地址上冲突,需寻找下一个空的哈希地址: 由H1=(Hash(29)+1) mod 11=8,哈希地址8为空,将29存入。
另外,22、8同样在哈希地址上有冲突,也是由H1找到空的哈希地址的; 7/25/202451 而Hash(3)=3,哈希地址上冲突,由 H1=(Hash(3)+1) mod 11=4 仍然冲突; H2=(Hash(3)+2) mod 11=5 仍然冲突; H3=(Hash(3)+3) mod 11=6 找到空的哈希地址,存入 线性探测法可能使第i个哈希地址的同义词存入第i+1个哈希地址,这样本应存入第i+1个哈希地址的元素变成了第i+2个哈希地址的同义词,……,因此,可能出现很多元素在相邻的哈希地址上“堆积”起来,大大降低了查找效率为此,可采用二次探测法,或双哈希函数探测法,以改善“堆积”问题7/25/2024522. 二次二次探探测法法 Hi=(Hash(key)±di) mod m 其中: Hash(key)为哈希函数 m为哈希表长度,m要求是某个4k+3的质数(k是整数) di 为增量序列 12,-12,22,-22,……,q2,-q2且q≤ (1/2)*(m-1)【【例例9.139.13】】关关键键码码集集为为 {47,,7,,29,,11,,16,,92,,22,,8,,3},,用二次探测法处理冲突,建表如下:用二次探测法处理冲突,建表如下: 0123456789101122347921672987/25/202453对关键码寻找空的哈希地址只有3这个关键码与上例不同, Hash(3)=3,哈希地址上冲突,由 H1=(Hash(3)+12) mod 11=4 仍然冲突; H2=(Hash(3)-12) mod 11=2 找到空的哈希地址,存入。
3. 双哈希函数探测法双哈希函数探测法 Hi=(Hash(key)+i*ReHash(key)) mod m (i=1,2,……,m-1) 其中: Hash(key),ReHash(key)是两个哈希函数, m为哈希表长度7/25/202454双哈希函数探测法,先用第一个函数Hash(key)对关键码计算哈希地址,一旦产生地址冲突,再用第二个函数ReHash(key)确定移动的步长因子,最后,通过步长因子序列由探测函数寻找空的哈希地址 比如,Hash(key)=a时产生地址冲突,就计算ReHash(key)=b,则探测的地址序列为 H1=(a+b) mod m,H2=(a+2b) mod m,……,Hm-1=(a+(m-1)b) mod m 二二. 拉链法拉链法 设哈希函数得到的哈希地址域在区间[0,m-1]上,以每个哈希地址作为一个指针,指向一个链,即分配指针数组 ElemType *eptr[m];建立m个空链表,由哈希函数对关键码转换后,映射到同一哈希地址i的同义词均加入到*eptr[i]指向的链表中。
7/25/202455【例【例9.l4】】关键码序列为关键码序列为47,7,29,11,16,92,22,8,3,50,37,89,47,7,29,11,16,92,22,8,3,50,37,89,94,2194,21,哈希函数为,哈希函数为 Hash(key)=key mod 11 Hash(key)=key mod 11,建表如下图,建表如下图 012^3456789^102289^33716^94298^21^11^47^92^50^7^拉拉链链法法处处理理冲冲突突时时的的哈哈希希表表((向向链链表表中中插插入入元元素素均均在在表表头头进进行行))7/25/202456【算法【算法9.109.10】】#define m 11#define m 11int CreateHashTbl(NodeType **l_tbl,ElemType *eptr)int CreateHashTbl(NodeType **l_tbl,ElemType *eptr){ { /* /* 建建立立哈哈希希表表,,l_tbl l_tbl 为为指指向向m m个个哈哈希希地地址址对对应应的的链链表表指指针针数数组组基基址址,,eptreptr为为待待放放入入哈哈希希表表的的元元素素基基址址,, 建建表表成成功功返返回回 1 1,否则,,否则, 返回返回0 */0 */intintfinished;finished;InitLinkTbl(l_tbl);InitLinkTbl(l_tbl); /* /* 初初始始化化指指向向链链表表的的指指针针数数组组 */ */for(;eptr->key!=0;eptr++)for(;eptr->key!=0;eptr++){ { /* /* 待待放放入入哈哈希希表表的的元元素素表表,, 关关键键码码0 0表表示示结结束束位位置置 */*/finished=MovElemToHashTbl(eptr,linktbl,Hash(eptr-finished=MovElemToHashTbl(eptr,linktbl,Hash(eptr->key)); >key)); if(!finished)if(!finished)break;break;} }return finished;return finished;} }7/25/202457InitLinkTbl(NodeType **l_tbl)InitLinkTbl(NodeType **l_tbl){int i;{int i;for(i=0;ielem=*e_addr;q->elem=*e_addr;q-q->nptr=*(l_tbl+h_addr);>nptr=*(l_tbl+h_addr);*(l_tbl+h_addr)=q;*(l_tbl+h_addr)=q;status=1;status=1;} }return status;return status;} }7/25/202458三三三三. . . . 建立一个公共溢出区建立一个公共溢出区建立一个公共溢出区建立一个公共溢出区 设设哈哈希希函函数数产产生生的的哈哈希希地地址址集集为为[0[0,,m-1]m-1],,则则分分配两个表:配两个表: 一一个个基基本本表表 ElemType ElemType base_tbl[m]base_tbl[m];;每每个个单单元元只只能存放一个元素;能存放一个元素; 一一个个溢溢出出表表 ElemType ElemType over_tbl[k]over_tbl[k];;只只要要关关键键码码对对应应的的哈哈希希地地址址在在基基本本表表上上产产生生冲冲突突,,则则所所有有这这样样的的元元素素一一律律存存入入该该表表中中。
查查找找时时,,对对给给定定值值kxkx通通过过哈哈希希函函数数计计算算出出哈哈希希地地址址i i,,先先与与基基本本表表的的base_tbl[i]base_tbl[i]单单元元比比较较,,若若相相等等,,查查找找成成功功;;否否则则,,再再到到溢溢出出表表中中进进行查找7/25/2024599.4.4 哈希表的查找分析哈希表的查找分析 哈哈希希表表的的查查找找过过程程基基本本上上和和造造表表过过程程相相同同一一些些关关键键码码可可通通过过哈哈希希函函数数转转换换的的地地址址直直接接找找到到,,另另一一些些关关键键码码在在哈哈希希函函数数得得到到的的地地址址上上产产生生了了冲冲突突,,需需要要按按处处理理冲冲突突的的方方法法进进行行查查找找在在介介绍绍的的三三种种处处理理冲冲突突的的方方法法中中,,产产生生冲冲突突后后的的查查找找仍仍然然是是给给定定值值与与关关键键码码进进行行比比较较的的过过程程所所以以,,对对哈哈希希表表查查找找效效率率的量度,依然用平均查找长度来衡量的量度,依然用平均查找长度来衡量 查查找找过过程程中中,,关关键键码码的的比比较较次次数数,,取取决决于于产产生生冲冲突突的的多多少少,,产产生生的的冲冲突突少少,,查查找找效效率率就就高高,,产产生生的的冲冲突突多多,,查查找找效效率率就就低低。
因因此此,,影影响响产产生生冲冲突突多多少少的的因因素素,,也也就就是是影影响响查查找找效效率率的的因因素素影影响响产产生生冲突多少有以下三个因素:冲突多少有以下三个因素: 1. 1. 哈希函数是否均匀;哈希函数是否均匀; 2. 2. 处理冲突的方法;处理冲突的方法; 3. 3. 哈希表的装填因子哈希表的装填因子7/25/202460 分析这三个因素,尽管哈希函数的分析这三个因素,尽管哈希函数的“好坏好坏”直直接影响冲突产生的频度,但一般情况下,我们总认接影响冲突产生的频度,但一般情况下,我们总认为所选的哈希函数是为所选的哈希函数是“均匀的均匀的”,因此,可不考虑,因此,可不考虑哈希函数对平均查找长度的影响就线性探测法和哈希函数对平均查找长度的影响就线性探测法和二次探测法处理冲突的例子看,如【例二次探测法处理冲突的例子看,如【例9.129.12】和【】和【例例9.139.13】相同的关键码集合、同样的哈希函数,但】相同的关键码集合、同样的哈希函数,但在数据元素查找等概率情况下,它们的平均查找长在数据元素查找等概率情况下,它们的平均查找长度却不同:度却不同:线性探测法的平均查找长度线性探测法的平均查找长度ASL=(5ASL=(5×1+31+3×2+12+1×4)/9=5/34)/9=5/3二次探测法的平均查找长度二次探测法的平均查找长度 ASL=(5ASL=(5×1+31+3×2+12+1×2)/9=13/92)/9=13/9哈希表的装填因子定义为:哈希表的装填因子定义为:αα =填入表中的元素个数填入表中的元素个数哈希表的长度哈希表的长度7/25/202461α是哈希表装满程度的标志因子。
由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小实际上,哈希表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数以下给出几种不同处理冲突方法的平均查找长度:7/25/202462处理冲突的方法平均查找长度查找成功时查找不成功时线性探测法二次探测法与双哈希法拉链法 哈希方法存取速度快,也较节省空间,静态查找、动态查找均适用,但由于存取是随机的,因此,不便于顺序查找7/25/202463。