详谈哈希表

一、基本概念

根据设定的哈希函数 H ( k e y ) H(key) H(key) 和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表便称为 哈希表,这一映像过程称为哈希造表散列,所得存储位置称哈希地址散列地址

二、哈希函数的构造方式

什么是好的哈希函数?

若对于关键字集合中的任何一个关键字,经哈希函数映射到地址集合中任何一个地址的概率是相等的,则称此类哈希函数为 均匀的哈希函数 。换句话说,就是使关键字经过哈希函数得到一个“随机的地址”,以便使一组关键字的哈希地址均匀分布在整个区间中,从而减少冲突。

常用的构造哈希函数的方法有:

1、直接定址法

取关键字或关键字的某个线性函数值为哈希地址。即:

H ( k e y ) = k e y   或   H ( k e y ) = a ∗ k e y + b H(key)=key \ 或 \ H(key)=a*key+b H(key)=key  H(key)=akey+b

其中 a a a b b b为常数(这种哈希函数叫做自身函数)。

例如:有一个从1岁到100岁的人口数字统计表,其中,年龄作为关键字,哈希函数取关键字减一常数1: H ( k e y ) = k e y + ( − 1 ) H(key)=key+(-1) H(key)=key+(1)。结果如下图所示:

CSDN图标
2、数字分析法

假设关键字是以 r r r 为基的数(如:以10位基的十进制),并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。

例:假设有80记录,其关键字为8位十进制数。假设哈希表的表长为100,则可取两位十进制数组成哈希地址。取哪两位?原则是使得到的哈希地址尽量避免产生冲突。

CSDN图标

对关键字分析发现,第1、2位都是“8 1”,第3位只能取1、2、3或4,第8位只能取2、5或7,因此这4位都不可取。由于中间的4位可看成是近乎随机的,因此可取其中任意两位,或取其中两位与另外两位的叠加求和后舍去进位作为哈希地址。可通过下面的式子获取4、5两位数。
H ( k e y ) = k e y % 100000 / 1000 H(key)=key\%100000/1000 H(key)=key%100000/1000

3、平方取中法

取关键字平方后的中间几位为哈希地址。这是一种较常用的构造哈希函数的方法。通常在选定哈希函数时不一定能知道关键字的全部情况,取其中哪几位也不一定合适,而一个数平方后的中间几位数和数的每一位都相关,由此使随机分布的关键字得到的哈希地址也是随机的。取的位数由表长决定。

4、折叠法

将关键字分割成位数相同的几部分(最后一部分的位数可能不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法。关键字位数很多,而且关键字中每一位上数字分布大致均匀时,可以采用折叠法得到哈希地址。

(1)移位叠加:移位叠加是将分割后的每一部分的最低位对齐,然后相加。

(2)间界叠加:间界叠加是从一端向另一端沿分割界来回折叠,然后对齐相加。

例:设某图书馆的馆藏图书不足10000种,现欲以国际标准图书编号为关键字构造哈希表,试用折叠法设计哈希函数。如有国际标准图书编号0-442-20586-4分别用(a)移位叠加法和(b)间界叠加法的哈希地址分别如下所示:

CSDN图标
5、除留余数法

取关键字被某个不大于哈希表表长 m m m的数 p p p除后所得余数为哈希地址。即
H ( k e y ) = k e y M O D p ,   p ≤ m H(key)=key \quad MOD \quad p,\ p \leq m H(key)=keyMODp, pm

这是一种最简单,也最常用的构造哈希函数的方法。它不仅可以对关键字直接取模(MOD),也可在折叠、平方取中法等运算后取模。

例:设有一组关键字如下:(19,14,23,01,68,20,84,27,55,11,10,79),试用除留取余法设计哈希函数。

可令 p p p 为13,即令 H ( k e y ) = k e y % 13 H(key)=key\%13 H(key)=key%13

注:对 p p p 要加一个限制: p p p一定要为质数。不然会增加冲突的可能。

6、随机法

选择一个随机函数,取关键字的随机函数值为它的哈希地址,即 H ( k e y ) = r a n d o m ( k e y ) H(key)=random(key) H(key)=random(key),其中 r a n d o m random random 为随机函数。通常,当关键字长度不等时采用此法构造哈希函数较恰当。

实际工作中需视不用的情况采用不同的哈希函数。通常,考虑的因素有:

(1)计算哈希函数所需时间(包括硬件指令的因素);

(2)关键字的长度;

(3)哈希表的大小

(4)关键字的分布情况;

(5)记录的查找频率

三、处理冲突的方法

处理冲突是指对于一个待插入哈希表的数据元素,若按给定的哈希函数求得的哈希地址已被占用,则按一定规则求下一个哈希地址,如此反复,直至找到一个可用的地址以保存该元素。

通常用的处理冲突的方法有以下几种:

1、开放定址法:

H i = ( H ( k e y ) + d i )   M O D   m    ; i = 1 , 2 , . . . , k ( k ≤ m − 1 ) H_i =(H(key)+d_i) \ MOD \ m \ \ ;i=1, 2,...,k(k\leq m-1) Hi=(H(key)+di) MOD m  ;i=1,2,...,k(km1)

其中: H ( k e y ) H(key) H(key) 为哈希函数; m m m为哈希表表长; d i d_i di为增量序列,可有下列3中取法;(1) d i = 1 , 2 , 3 , . . . , m − 1 d_i=1,2,3,...,m-1 di=1,2,3,...,m1,称 线性探测再散列(2) d i = 1 2 , − 1 2 , 2 2 , − 2 2 , 3 2 , . . . , ± k 2 , ( k ≤ m / 2 ) d_i=1^2,-1^2,2^2,-2^2,3^2,...,\pm k^2,(k\leq m/2) di=12,12,22,22,32,...,±k2(km/2)二次探测再散列(3) d i = d_i= di= 伪随机数序列,称伪随机探测再散列。

例:设有一组关键字如下:(67,84,18,26,34,28),哈希函数为 H ( k e y ) = k e y H(key)=key%7 H(key)=key, 用线性探测再散列法处理冲突,试画出哈希表存储结构示意图。
已知:

    哈希函数: H ( k e y ) = k e y % 7 H(key)=key\%7 H(key)=key%7

    有冲突时: H i = ( H ( k e y ) + d i ) % 7 H_i=(H(key)+d_i)\%7 Hi=(H(key)+di)%7

CSDN图标
2、再哈希法

H i = R H i ( k e y )      i = 1 , 2 , . . . , k H_i=RH_i(key) \ \ \ \ i=1,2,...,k Hi=RHi(key)    i=1,2,...,k

R H I RH_I RHI均是不同的哈希函数,即在同义词产生地址冲突时计算另一个哈希函数地址,直到冲突不再发生。这种方法不易产生“聚集”,但增加了计算的时间。

3、链地址法

将所有关键字为同义词的记录存储在同一线性链表中,假设某哈希函数产生的哈希地址在区间 [ 0 , m − 1 ] [0,m-1] [0,m1] 上,则设立一个指针型向量
C h a i n   C h a i n   H a s h [ m ] Chain \ Chain \ Hash[m] Chain Chain Hash[m]

其每个分量的初始状态都是空指针。凡哈希地址为 i i i的记录都插入到头指针为 C h a i n   H a s h [ i ] Chain \ Hash[i] Chain Hash[i] 的链表中。在链表中的插入位置可以在表头或表尾;也可以在中间,以保持同义词在同一线性表中按关键字有序。

例:已知一组关键字为(67,84,18,26,34,28),哈希函数为 H ( k e y ) = k e y % 7 H(key)=key\%7 H(key)=key%7 ,用链地址法处理冲突,试画出哈希表存储结构示意图。

已知:

   哈希函数: H ( k e y ) = k e y % 7 H(key)=key\%7 H(key)=key%7

   有冲突时,在对应链表中插入新节点

CSDN图标
4、公共溢出区法

这也是处理冲突的一种方法。假设哈希函数的值域为 [ 0 , m − 1 ] [0,m-1] [0,m1] ,则设向量 H a s h T a b l e [ 0.. m − 1 ] HashTable[0..m-1] HashTable[0..m1] 为基本表,每个分量存放一个记录,另设立向量 O v e r T a b l e [ 0.. v ] OverTable[0..v] OverTable[0..v] 为溢出表。所有关键字和基本表中关键字为同义词的记录,不管它们由哈希函数得到的哈希地址是什么,一旦发生冲突,都填入溢出表。

例:设有一组关键字如下:(67,84,18,26,34,28),哈希函数为 H ( k e y ) = k e y % 7 H(key)=key\%7 H(key)=key%7 ,用公共溢出区法处理冲突,试画出哈希表存储结构示意图。

已知:

   哈希函数: H ( k e y ) = k e y % 7 H(key)=key\%7 H(key)=key%7

   有冲突时,保存到公共溢出区

CSDN图标

四、在哈希表中查找元素

在哈希表上进行查找的过程和哈希造表的过程基本一致。给定 K K K 值,根据造表时设定的哈希函数求得哈希地址。

  • 若表中此位置上没有记录,则查找不成功;
  • 否则比较关键字,若和给定值相等,则查找成功;
  • 否则根据造表时设定的处理冲突的方法找“下一地址”,直至哈希表中某个位置为“空”或者表中所填记录的关键字等于给定值时为止。
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在JavaScript中,哈希表可以通过对象(Object)来实现。对象的属性名就是哈希表中的键,属性值就是哈希表中的值。以下是一个简单的哈希表的实现: 1. 定义一个HashTable类,包含以下方法: ```javascript class HashTable { constructor() { this.table = {}; } // 向哈希表中添加键值对 put(key, value) { this.table[key] = value; } // 从哈希表中获取指定键的值 get(key) { return this.table[key]; } // 从哈希表中移除指定键的值 remove(key) { delete this.table[key]; } // 判断哈希表中是否包含指定键 contains(key) { return this.table.hasOwnProperty(key); } // 获取哈希表中所有的键 getKeys() { return Object.keys(this.table); } // 获取哈希表中所有的值 getValues() { return Object.values(this.table); } // 获取哈希表中键值对的数量 size() { return Object.keys(this.table).length; } // 清空哈希表 clear() { this.table = {}; } } ``` 2. 创建一个HashTable对象,并向其中添加键值对: ```javascript const hashTable = new HashTable(); hashTable.put('name', 'Tom'); hashTable.put('age', 18); hashTable.put('gender', 'male'); ``` 3. 从哈希表中获取指定键的值: ```javascript const name = hashTable.get('name'); // 'Tom' ``` 4. 从哈希表中移除指定键的值: ```javascript hashTable.remove('gender'); ``` 5. 判断哈希表中是否包含指定键: ```javascript const hasAge = hashTable.contains('age'); // true const hasGender = hashTable.contains('gender'); // false ``` 6. 获取哈希表中所有的键: ```javascript const keys = hashTable.getKeys(); // ['name', 'age'] ``` 7. 获取哈希表中所有的值: ```javascript const values = hashTable.getValues(); // ['Tom', 18] ``` 8. 获取哈希表中键值对的数量: ```javascript const size = hashTable.size(); // 2 ``` 9. 清空哈希表: ```javascript hashTable.clear(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值