哈希函数的构造方法(1)

哈希函数的构造方法

本文阐述了哈希函数的构造方法有很多,但应注意两个原则:第一,函数值应在1至记录总数之间;第二,尽可能避免冲突。

设要存放的数据元素有n个,存放数据元素的内存单元有m个,设计哈希函数的目标就是要使通过哈希函数得到的n个数据元素的哈希地址尽可能均匀地分布在m个连续内存单元上,同时使计算过程尽可能简单以达到尽可能高的时间效率。

 

 

                

引 言

构造哈希函数的方法很多。如何构造一个“好”的哈希函数是很强的技术性和实践性问题,这里的“好”指的是哈希函数构造比较简单,并且用此哈希函数产生的映射所发生的冲突可能性最小,换句话说一个好的哈希函数能将给定数据集合均匀地映射到给定的地址区间中。

Hash的原意是“弄乱,切碎”,这里的含义是“杂凑”。基本做法是,根据集合元素值的分布情况,设计一个哈希函数h(ki),存储之素ki时,计算ki的哈希函数值,元素ki存储在a(h)中。

如果“幸运”,所设计的哈希函数很均匀,即任何ki≠kj,都有h(ki)≠h(kj),那么在查找ki时(再计算ki的哈希函数函数值h),就能在a[h]中找到元素ki。

1.直接定址法

  直接定址法是以数据元素关键字k本身或它的线性函数作为它的哈希地址,即:H(k)=k  或 H(k)=a×k+b ; (其中a,b为常数)

  例1,有一个人口统计表,记录了从1岁到100岁的人口数目,其中年龄作为关键字,哈希函数取关键字本身,如图(1):

地址

A1

A2

……

A99

A100

年龄

1

2

……

99

100

人数

980

800

……

495

107

可以看到,当需要查找某一年龄的人数时,直接查找相应的项即可。如查找99岁的老人数,则直接读出第99项即可。这种哈希函数简单,并且对于不同的关键字不会产生冲突,但可以看出这是一种较为特殊的哈希函数,实际生活中,关键字的元素很少是连续的。用该方法产生的哈希表会造成空间大量的浪费,因此这种方法适应性并不强。[2]↑

2.数字分析法

 2.1数字分析法是取数据元素关键字中某些取值较均匀的数字位作为哈希地址的方法。即当关键字的位数很多时,可以通过对关键字的各位进行分析,丢掉分布不均匀的位,作为哈希值。它只适合于所有关键字值已知的情况。通过分析分布情况把关键字取值区间转化为一个较小的关键字取值区间。

   例2,要构造一个数据元素个数n=80,哈希长度m=100的哈希表。不失一般性,我们这里只给出其中8个关键字进行分析,8个关键字如下所示:

K1=61317602      K2=61326875      K3=62739628      K4=61343634

K5=62706815      K6=62774638      K7=61381262      K8=61394220

分析上述8个关键字可知,关键字从左到右的第1、2、3、6位取值比较集中,不宜作为哈希地址,剩余的第4、5、7、8位取值较均匀,可选取其中的两位作为哈希地址。设选取最后两位作为哈希地址,则这8个关键字的哈希地址分别为:2,75,28,34,15,38,62,20。[1]↑

2. 2设有n个d 位数,每一位可能有r种不同的符号,这r种不同的符号在各位上出现的频率不一定相同,可能在某位上分布均匀些,每种符号出现的机会均等;在某位上分布不均匀,只有某几种符号经常出现。可根据哈希表的大小,选取其中各种符号分布均匀的若干位作为哈希地址。计算各位数字中符号分布均匀度rk的公式为:rk=其中,aki表示第i个符号k位上出现的的期望值。计算出rk值越小,

i=1

表明在该位(第k位)各种符号分布越不均匀。 

例3,有一组关键字,对其各位编码如下:

9   2   1   4   8

9   1   2   6   9

9   0   5   2   7

9   1   6   3   0

9   1   8   0   5

9   1   5   5   8

9   2   0   4   7

9   0   0   0   1   

①  ②  ③  ④  ⑤

①位仅“9”出现8次r1=(8-8/10)2*1+(0-8/10)2*9=57.60

②位“0,2”各出现2次,“1”出现4次r2=(2-8/10)2*2+(4-8/10)2*1+(0-8/10)2*7=17.60

③位“0,5”各出现2次,“1,2,6,8”各出现1次r3=(2-8/10)2*2+(1-8/10)2*4+(0-8/10)2*4=5.60

④位“0,4”各出现2次,“2,3,5,6”各出现1次

⑤位“7,8”各出现2次,“0,1,5,9”各出现1次

r3 =r4 =r5 =5.60

若哈希表地址范围有3位数字,取各关键字的③④⑤位作为记录的哈希地址。也可以把第①②和第⑤位想加,舍去进位,变成一位数,再与第③④位合起来哈希地址等。显然数字分析法仅适用于事先知道表中所有关键字每一位数值的分布情况,它完全依赖于关键字集合。如果换一个关键字集合,选择哪几位重新决定。

3.折叠法

  所谓折叠法是将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位),这方法称为折叠法。这种方法适用于关键字位数较多,而且关键字中每一位上数字分布大致均匀的情况。

  折叠法中数位折叠又分为移位叠加和边界叠加两种方法,移位叠加是将分割后是每一部分的最低位对齐,然后相加;边界叠加是从一端向另一端沿分割界来回折叠,然后对齐相加。

例4,当哈希表长为1000时,关键字key=110108331119891,允许的地址空间为三位十进制数,则这两种叠加情况如图(2):

       移位叠加                                 边界叠加

       8 9 1                                     8 9 1

       1 1 9                                     9 1 1

       3 3 1                                     3 3 1

       1 0 8                                     8 0 1

    +  1 1 0                                   + 1 1 0              

   (1) 5 5 9                                  (3)0 4 4

                 图(2)由折叠法求哈希地址

     用移位叠加得到的哈希地址是559,而用边界叠加所得到的哈希地址是44。如果关键字不是数值而是字符串,则可先转化为数。转化的办法可以用ASCⅡ字符或字符的次序值。[3]↑


4.平方取中法

  这是一种常用的哈希函数构造方法。这个方法是先取关键字的平方,然后根据可使用空间的大小,选取平方数是中间几位为哈希地址。

哈希函数 H(key)=“key2的中间几位”因为这种方法的原理是通过取平方扩大差别,平方值的中间几位和这个数的每一位都相关,则对不同的关键字得到的哈希函数值不易产生冲突,由此产生的哈希地址也较为均匀。

例5,若设哈希表长为1000则可取关键字平方值的中间三位,如图(3)所示:

关键字

关键字的平方

哈希函数值

1234

1522756

227

2143

4592449

924

4132

17073424

734

3214

10329796

297

图(3)平方取中哈希函数示例    [4] ↑

有人曾用“轮盘赌”的统计分析方法对它们进行了模拟分析,结论是平方取中法最接近“随机化”。

 

  例6,设有一组关键字值为ABC,BCD,CDE,DEF其相应的机内码分别为010203,020304,030405,040506。假设可利用地址空间大小为103,平方后取平方数的中间三位作为相当记录的存储地址。如图(4)所示:         

关键字

机内码

机内码的平方

哈希地址

ABC

010203

0104101209

101

BCD

020304

0412252416

252

CDE

030405

0924464025

464

DEF

040506

1640736036

736

图(4)平方取中法关键字及其存储地址[6]↑

   下面给出平方取中法的哈希函数

     //平方取中法哈希函数,结设关键字值32位的整数

     //哈希函数将返回key * key的中间10位

       Int  Hash (int key)

         {

     //计算key的平方

      Key * = key ;

     //去掉低11位

     Key>>=11;

     // 返回低10位(即key * key的中间10位)

       Return key %1024;

          }



5.减去法

   减去法是数据的键值减去一个特定的数值以求得数据存储的位置。

例7,公司有一百个员工,而员工的编号介于1001到1100,减去法就是员工编号减去1000后即为数据的位置。编号1001员工的数据在数据中的第一笔。编号1002员工的数据在数据中的第二笔…依次类推。从而获得有关员工的所有信息,因为编号1000以前并没有数据,所有员工编号都从1001开始编号。

 

6.基数转换法

  将十进制数X看作其他进制,比如十三进制,再按照十三进制数转换成十进制数,提取其中若干为作为X的哈希值。一般取大于原来基数的数作为转换的基数,并且两个基数应该是互素的。

 

例8,Hash(80127429)=(80127429)13=8*137+0*136+1*135+2*134+7*133+4*132+2*131+9=(502432641)10如果取中间三位作为哈希值,得Hash(80127429)=432

 为了获得良好的哈希函数,可以将几种方法联合起来使用,比如先变基,再折叠或平方取中等等,只要散列均匀,就可以随意拼凑。[5] ↑


原文地址:http://wenku.baidu.com/view/61b121c06137ee06eff918c1.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值