哈希表

来源:互联网 发布:各区县地图json 编辑:程序博客网 时间:2024/06/10 10:43

哈希表(HashTable)也叫散列表,是根据关键码值(KeyValue)而直接进行访问的数据结构。它通过把关键码值映射到哈希表中的一个位置来访问记录,以加快查找的速度。这个映射函数就叫做散列函数,存放记录的数组叫做散列表。

散列存储的基本思路就是以数据中每个元素的关键字K为自变量,通过散列函数H(k)计算出函数值,以该函数值作为一块连续存储空间的的单元地址,将该元素存储到函数值对应的单元中。

哈希表存储的是键值对,其查找的时间复杂度与元素数量多少无关,哈希表在查找元素时是通过计算哈希码值来定位元素的位置从而直接访问元素的,因此,哈希表查找的时间复杂度为O(1)。

对不同的关键字可能得到同一哈希地址,即k1不等于k2但是f(k1)=f(k2)。这种现象叫做冲突。一般情况下,冲突只能尽可能少,而不能完全避免。所以要考虑如何解决冲突。

下面介绍几种常用的哈希函数构造方法:

第一种,直接定址法

取关键字或关键字的某个线性函数值为哈希地址,即H(Key)=Key或者H(Key)=a*Key+b(a,b为整数)。举一个例子。我们的函数为H=key-1948.哈希表如下:


如果要查1970年出生的人数,则只需要查第(1970-1848)=22项即可。

由于直接定址法所得地址集合和关键字集合的大小相同,所以不会发生冲突,但是实际中只用这种哈希函数的情况很少。

 第二种,数字分析法

分析一组数据,比如一组员工的出生年月,这时我们发现出生年月的前几位数字一般都相同,因此,出现冲突的概率就会很大,但是我们发现年月日的后几位表示月份和具体日期的数字差别很大,如果利用后面的几位数字来构造散列地址,则冲突的几率则会明显降低。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址

第三种,平方取中法

取关键字平方后的中间几位为哈希地址,这是一种较常用的构造哈希函数的方法,通常在选定哈希函数时不一定能知道关键字的全部情况,取其中哪几位也不一定合适的情况下使用。

第四种,折叠法

将关键字分割为位数相同的几部分(最后一部分位数可以不同),然后取各部分叠加和作为哈希地址。关键字位数很长,关键字中每一位上数字分布大致均匀时,可以采用该方法。

第五种,除留余数法

取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址.即H(Key)=Key MOD p,p<=m.不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选得不好,则很容易产生冲突。

第六种,随机数法

选择一个随机函数,取关键字的随机值作为散列地址,通常用于关键字长度不同的场合。

 

下面介绍哈希表如何处理冲突:

第一种,开放地址法

也叫再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式:Hi=(H(key)+di)%m   i=1,2,…,n,其中H(key)为哈希函数,m 为表长,di称为增量序列。其中di有三种取法:

         di=1,2,3,…,m-1,称为线性探测再散列;

         di=12,-12,22,-22…,k2。称为二次探测再散列;

         di=伪随机探测再散列。

第二种,再哈希法

         这种方法是同时构造多个不同的哈希函数:

        Hi=RH1(key),i=1,2,3,…,n.

        当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间

第三种,链地址法

         将所有关键字为同义词的记录存储在同一线性链表中。也就是哈希地址相同的元素构成一个单链表,并将单链表的头指针存在哈希表的第i个单元中。

         举一个例子,一组关键字为(19,14,23,01,68,20,84,27,55,11,10,79) 按照哈希函数H=key MOD 13 和链地址法得到结构图如下:


和开放地址法相比,该方法具有如下有点:

非同义词不会发生冲突,平均查找长度较短;

由于各链表结构是动态申请的,所以适合无法确定表长的情况;

删除结点操作易于实现。    

第四种,建议公共溢出区

建立一个溢出表,所有关键字和基本表中关键字为同义词的记录,一旦冲突,都填入溢出表。



2 0
原创粉丝点击