1、1,8.3 哈希表,8.3.1 什么是哈希表 8.3.2 构造哈希函数的几种方法 8.3.3 处理冲突的方法 8.3.4 哈希表的查找及其性能分析,2,8.3.1 什么是哈希表,以上两节讨论的表示查找表的各种结构的共同特点:记录在表中的位置和它的关键字之间不存在一个确定的关系, 查找的过程为给定值依次和关键字集合中各个关键字进行比较, 查找的效率取决于和给定值进行比较的关键字个数。 用这类方法表示的查找表,其平均查找长度都不为零。,3,问题:对于频繁使用的查找,我们希望平均查找长度ASL接近于0,预先知道所查关键字在表中的位置 记录在表中位置和其关键字之间存在一种确定的关系,只有一个办法,4,
2、例如:为每年招收的 1000 名新生建立一张查找表,其关键字为学号,其值的范围为 xx000 xx999 (前两位为年份)。若以下标为000 999 的顺序表表示学号 查找过程可以简单进行: 取给定值(学号)的后三位,不需要经过比较便可直接从顺序表中找到待查关键字。,5,哈希查找的基本思想:在记录的存储地址和它的关键字之间建立一个确定的对应关系;这样,不经过比较,一次存取就能得到所查元素的查找方法 哈希函数:在记录的关键字与记录在表中的存储位置之间建立一个函数关系,以 f(key) 作为关键字为 key 的记录在表中的位置,通常称这个函数 f(key) 为哈希函数。 哈希地址:由哈希函数求出的
3、记录存储位置称为哈希地址,表示成:addr(ai)=f(ki) ai是表中的一个元素(记录) addr(ai)是ai的存储地址 ki是ai的关键字,6,哈希表:应用哈希函数,由记录的关键字确定记录在表中的地址,并将记录放入此地址,这样构成的表叫 哈希查找:又叫散列查找,利用哈希函数进行查找的过程叫,7,Zhao, Qian, Sun, Li, Wu, Chen, Han, Ye, Dai,例:对于如下 9 个关键字,Chen,Zhao,Qian,Sun,Li,Wu,Han,Ye,Dai,问题: 若添加关键字 Zhou , 怎么办?,能否找到另一个哈希函数?,设 哈希函数f(key) = (AS
4、C(关键字第一个字母) -ASC(A)+1)/2,8,哈希函数是一个映象,即 将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地址集合的 大小不超出允许范围即可; 由于哈希函数是一个压缩映象,因此,在一般情况下,很容易产生“冲突”现象, 即: key1 key2, 而 f(key1) = f(key2) 很难找到一个不产生冲突的哈希函数。一般情况下,只能选择恰当的哈希函数,使冲突尽可能少地产生。 在构造哈希表时,除了需要选择一个“好”(尽可能少产生冲突)的哈希函数之外;还需要找到一种处理冲突 的方法。,9,8.3.2 构造哈希函数的几种方法,对数字的关键字可有下列构造方法,若是非数
5、字关键字,则需先对其进行数字化处理,1. 直接定址法,3. 平方取中法,5. 除留余数法,4. 折叠法,6. 随机数法,2. 数字分析法,10,1. 直接定址法,构造:取关键字或关键字的某个线性函数作哈希函数H(key) = key或者 H(key) = a. key + b 特点 直接定址法所得地址集合与关键字集合大小相等,不会发生冲突 实际中能用这种哈希函数的情况很少,11,2. 数字分析法,构造:对关键字进行分析,取关键字的若干位或其组合作哈希地址 特点:适于关键字位数比哈希地址位数大,且可能出现的关键字事先知道的情况,12,3. 平方取中法,构造:以关键字的平方值的中间几位作为存储地址
6、。求“关键字的平方值” 的目的是“扩大差别” ,同时平方值的中间各位又能受到整个关键字中各位的影响。 特点:关键字中的每一位都有某些数字重复出现频度很高的现象。,13,4. 折叠法,构造:将关键字分割成位数相同的几部分,然后取这几部分的叠加和(舍去进位)做哈希地址 种类 移位叠加:将分割后的几部分低位对齐相加 间界叠加:从一端沿分割界来回折送,然后对齐相加 特点:适于关键字位数很多,且每一位上数字分布大致均匀情况,14,例 关键字为 :0442205864,哈希地址位数为4,15,5. 除留余数法,构造:取关键字被某个不大于哈希表表长m的数p除后所得余数作哈希地址,即H(key)=key %
7、pp=m 且P 应为不大于 m 的素数或是不含20 以下的质因子 特点 简单、常用: 可与上述几种方法结合使用 p的选取很重要: p选的不好,容易产生同义词,对P要加一定的限制,16,给定一组关键字为:12, 39, 18, 24, 33, 21假定hash表的长度为12 若取 p=9, 则他们对应的哈希函数值将为: 3, 3, 0, 6, 6, 3,例如:,为什么要对 p 加限制?,若 p 中含质因子 3, 则所有含质因子 3 的关键字均映射到“3 的倍数”的地址上,从而增加了“冲突”的可能。,17,6.随机数法,构造:取关键字的随机函数值作哈希地址H(key)=random(key) 适于
8、关键字长度不等的情况,实际造表时,采用何种构造哈希函数的方法取决于建表的关键字集合的情况(包括关键字的范围和形态),总的原则是使产生冲突的可能性降到尽可能地小。,18,例 有80个记录,关键字为8位十进制数,哈希地址为2位十进制数, ,分析: 只取8只取1只取3、4只取2、7、5数字分布近乎随机 所以:取任意两位或两位与另两位的叠加作哈希地址,19,8.3.3 处理冲突的方法,处理冲突 :为产生冲突的地址寻找下一个哈希地址。 主要有二种方法 开放定址法 链地址法,20,思想:为产生冲突的关键字寻找一个新的地址 Hi(key), 求得一个地址序列:H0, H1, H2, , Hs 1 sm-1其
9、中:H0 = H(key)H1 = (H(key) + d1 ) % m H2 = (H(key) + d2 ) % m Hi = ( H(key) + di ) % m i=1, 2, , s,1.开放定址法,21,对增量 di 有三种取法 线性探测再散列:di=1,2,3,m-1 二次探测再散列:di=1,-1,2,-2,3,k 伪随机探测再散列:di=伪随机数序列 注意:增量 di 应具有“完备性”,即:产生的 Hi 均不相同,且所产生的 s个 Hi 值能覆盖哈希表中所有地址。要求: 平方探测时的表长 m 必为形如 4j+3 的素数(如: 7, 11, 19, 23, 等); 随机探测时
10、的 m 和 di 没有公因子。,22,例 表长为11的哈希表中已填有关键字为17,60,29的记录,H(key)=key % 11,现有第4个记录,其关键字为38,按三种处理冲突的方法,将它填入表中,(1) H(38)=38 % 11=5 冲突H1=(5+1) % 11=6 冲突H2=(5+2) % 11=7 冲突H3=(5+3) % 11=8 不冲突,38,(2) H(38)=38 % 11=5 冲突H1=(5+1) % 11=6 冲突H2=(5-1) % 11=4 不冲突,38,(3) H(38)=38 % 11=5 冲突设伪随机数序列为9,则:H1=(5+9) % 11=3 不冲突,38
11、,线性探测,二次探测,随机探测,23,将所有哈希地址相同的记录都链接在同一链表中 例:关键字集合 19, 01, 23, 14, 55, 68,11, 82, 36 哈希函数为:H(key)=key % 7,0 1 2 3 4 5 6,14,01,36,19,82,23,11,68,55,2. 链地址法,24,8.3.4 哈希表的查找及其性能分析,查找过程:和造表过程一致,对于给定值,由哈希函数和解决冲突的方法定位记录的存储位置。,25,例:给出哈希表HT,哈希函数 H(key)=key % 11,解决冲突方法:开放地址法中线性探测再散列Hi(key)=(H(KEY)+di)% 11 (d1=
12、1, d2=2, d3=3, ),试查找关键字19 、02,查找关键字19,用哈希函数求19 对应的哈希地址: H(19)=19 % 11=8,将HT8与19比较相等 查找成功,26,查找关键字02,用哈希函数求02 对应的哈希地址:H(02)=02 % 11=2,将HT2与02比较不相等,用解决冲突方法为02求下一个“地址” (取d1=1)H1 (02)=(H(02)+ d1)% 11=3,将HT3与02比较相等 查找成功,27,查找算法实现:开放定址哈希表,int hashsize = 997, . ; typedef struct ElemType *elem; int count; /
13、 当前数据元素个数int sizeindex; / hashsizesizeindex为当前容量 HashTable;#define SUCCESS 1 #define UNSUCCESS 0 #define DUPLICATE -1,28,bool SearchHash (HashTable H, KeyType K, int &p, int &c) / 在开放定址哈希表H中查找关键码为K的记录 / SearchHash,p = Hash(K); / 求得哈希地址,while (H.elemp.key != NULLKEY / 求得下一探查地址 p,if (K=H.elemp.key) re
14、turn 1; / 查找成功,返回待查数据元素位置 p,else return 0; / 查找不成功,29,bool InsertHash (HashTable &H, Elemtype e) ,c = 0;,if ( HashSearch ( H, e.key, p, c ) = SUCCESS )return DUPLICATE;/ 表中已有与 e 有相同关键字的元素,elseH.elemp = e; +H.count; return OK;/ 查找不成功时,返回 p为插入位置,else RecreateHashTable(H); / 重建哈希表,if ( c hashsizeH.size
15、index/2 ) / 冲突次数 c 未达到上限,(阀值 c 可调),30,哈希表查找分析 从查找过程得知,哈希表查找的平均查找长度实际上并不等于零。 =n/m 值的大小(n记录数,m表的长度),决定哈希表查找的ASL的因素:(1) 选用的哈希函数;(2) 选用的处理冲突的方法;(3) 哈希表饱和的程度,装载因子=n/m 值的大小(n记录数,m表的长度),31,一般情况下,可以认为选用的哈希函数是“均匀”的,则在讨论ASL时,可以不考虑它的因素。 因此,哈希表的ASL是处理冲突方法和装载因子的函数。 例: 关键字集合 7, 15, 20, 31, 48, 53,64, 76, 82, 99 ,线性探测处理冲突时, ASL =,平方探测处理冲突时, ASL =,链地址法处理冲突时, ASL =,2.4,2.0,1.7,32,线性探测再散列,链地址法,二次探测或随机探测再散列,可以证明:查找成功时有下列结果:,33,从以上结果可见:,哈希表的平均查找长度是 的函数,而不是 n 的函数。,这说明,用哈希表构造查找表时,可以选择一个适当的装填因子 ,使得平均查找长度限定在某个范围内。, 这是哈希表所特有的特点。,