1、哈希函数进行模除取余时,最好取素数进行模除。
【解析】哈希表设计目的就是希望尽量的随机散射,不希望这些在同一列上的元素(也就是会冲突的元素)之间具有关系,所以我们都采用素数作为哈希表的大小,从而避免模数相同的数之间具备公共因数。
① 如果用一个合数8作为哈希表大小,0-30在哈希表中的散射情况:
② 用质数7作为哈希表大小,0-30在哈希表中的散射情况:
2、哈希表装填因子(负载因子)定义为:α= 填入表中的元素个数 / 哈希表的长度
α是哈希表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。
3、哈希函数构造主要有以下几种:
- 1:直接寻址法;
- 2:取模法;
- 3:数字分析法;
- 4:折叠法;
- 5:平方取中法;
- 6:除留余数法;
- 7:随机数法。
4、Hash处理冲突的方法:
① 开放地址法:在得到Hash值后如果产生冲突,则加一个增量d,直至没有冲突的位置。
d的取法:
(1)线性探测再散列:1,2,3,4... 其实就是当发生冲突时,从该冲突位置逐个向后查找,类似于循环数组,直到找到合适的位置或者找遍整个表都未找到合适的位置。这个方法的缺点是易发生堆聚现象,堆聚就是存入哈希表的数据在表中连成一片。
【注】哈希查找中k个关键字具有同一哈希值,若用线性探测法将这k个关键字对应的记录存入哈希表中,至少要进行(k ( k + 1 ) / 2)次探测。--- 第一次算线性探测
【注】设有n个关键字具有相同的Hash函数值,则用线性探测法把这n个关键字映射到Hash表中需要做 n * (n - 1) / 2 次线性探测? --- 第一次不算线性探测
第一个关键字直接插入,第二个关键字要做1次探测,所以类推n个关键词要做0+1+2+...+(n-1) = n * (n - 1) / 2 。
(2)二次探测再散列(平方探测法):可以避免堆积问题。
【例题】设哈希表长为14,哈希函数是H(key)=key%11,表中已有数据的关键字为15,38,61,84共四个,现要将关键字为49的结点加到表中,用二次探测再散列法解决冲突,则放入的位置是( 9 )。
【解析】15%11 = 4,38%11 = 5,61%11 = 6,84%11 = 7.
要求49的位置:49%11 = 5,被占用了,使用二次探测再散列法,<1> (5+1^2)%14=6 冲突 <2> (5-1^2)%14=4 冲突 <3> (5+2^2)%14=9 不冲突,得到最终位置为9.
(3) 伪随机探测再散列。将步长改为随机数,这样使不同的关键字具有不同的探测顺序,可以有效避免堆聚。
② 再哈希表法:产生冲突时取不同的哈希函数计算,但缺点是不易产生“聚集”,增加计算时间。
③ 链地址法:拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短
【例题】设散列表的长度为8,散列函数H(k)=k mod 7,初始记录关键字序列为(32,24,15,27,20,13),计算用链地址法作为解决冲突方法的平均查找长度是(1.5)
【解析】链地址法作为解决冲突 方法:将所有关键字为同义词的记录存储在一个单链表中,并用一维数组存放头指针。
0 1 2 3 4 5 6
15 24 32 27
20
13
因此查找长度为 1、 1、 1、1、 2、3 等概率情况下查找成功时的平均查找长度为 9 / 6 = 1.5。
④ 建立一个公共溢出区。
5、Hash操作能根据散列值直接定位数据的存储地址,设计良好的hash表能在常数级时间下找到需要的数据,但是更适合于内存中的查找。
B+树是一种是一种树状的数据结构,适合做索引,对磁盘数据来说,索引查找是比较高效的
STL_Map的内部实现是一颗红黑树,但是只是一颗在内存中建立二叉树,不能用于磁盘操作,而其内存查找性能也比不上Hash查找。
因此三者中,对于内存中数据,查找性能较好的数据结构是Hash_Map,对于磁盘中数据,查找性能较好的数据结构是B+Tree。
6、设哈希表长度为11,哈希函数H(K)=(K的第一个字母在字母表中的序号) MOD 11,若输入顺序为(D,BA,TN,M,CI,I,K,X,TA),采用内散列表,处理冲突方法为线性
测法,要求构造哈希表,在等概率情况下查找成功平均查找长度为:20/9 。
【解析】
散列表 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
散列元素 |
K |
TN |
BA |
M |
D |
CI |
X |
TA |
I |
||
查找成功次数 |
1 |
4 |
1 |
2 |
1 |
3 |
5 |
1 |
2 |
||
查找失败次数 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
1 |
1 |
9 |
8 |
平均查找成功长度跟平均查找失败长度如下:
ASL suc =(1+4+1+2+1+3+5+1+2)/ 9 = 20 / 9
ASL fail =(7+6+5+4+3+2+1+1+1+9+8)/11 = 47 / 11
①
D=4mode11=4,1次 B=2mod11=2,1次 T=20mod11=9,1次 M=13mod11=2->3,2次 C=3mod11=3->4->5,3次 I=9mod11=9->10,2次
K=11mod11=0,1次 X=24mod11=2->3->4->5->6,5次 T=20mod11=9->10->0->1,4次
9个数字,共20次,所以20/9。
②
某个(哈希表中并不存在的)值n对11取余之后,结果可能是0~10
如果n mod 11的值是8、9、10那么1次查找之后就可以判定表中不存在这个值,
如果n mod 11 = 0,那么还需要偏移,一共9次查找才能判定表中没有这个值,
如果n mod 11 = 1,那么需要8次查找才能判定表中没有这个值,
如果n mod 11 = 2,那么需要7次查找才能判定表中没有这个值,……
如果n mod 11 = 7,那么需要2次查找才能判定表中没有这个值。所以不成功的平均查找长度就是上述查找次数取均值。
7、
① 索引仅满足“=”、“IN”和“<=>”查询,不能使用范围查询因为hash索引比较的是经常hash运算之后的hash值,因此只能进行等值的过滤,不能基于范围的查找,因为经过hash算法处理后的hash值的大小关系,并不能保证与处理前的hash大小关系对应。
② hash索引无法被用来进行数据的排序操作。由于hash索引中存放的都是经过hash计算之后的值,而hash值的大小关系不一定与hash计算之前的值一样,所以数据库无法利用hash索引中的值进行排序操作。
③ 对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。
④ Hash 索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高。对于选择性比较低的索引键,如果创建 Hash 索引,那么将会存在大量记录指针信息存于同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。
8、哈希表(Hash Table)是一种根据关键字直接访问内存存储位置的数据结构。通过哈希表,数据元素的存放位置和数据元素的关键字之间建立起某种对应关系。
A,hash函数可以把字符串等任意长度的输入映射成固定长度的整数,也就是哈希值。
C,哈希表建立了哈希值与原值信息存储之间的联系,可以通过哈希值查找到原值信息。
D,不同的信息产生相同的哈希值叫哈希冲突。设计哈希函数应尽量避免哈希冲突。因此一般很难冲突。
9、散列的基本思想是以结点的关键码作为自变量,通过散列函数将其映射到记录的存储地址。有时不同的关键码值经过同一散列函数计算后形成相同的存储地址,产生碰撞现象。由于处理碰撞的代价较大,应尽量避免。这就要求散列函数在作用于各记录关键码后的取值能同等均匀在存储空间上。
10、散列表的查找效率取决于:散列函数、处理冲突的方法和装填因子。
11、开哈希表-------链式地址法,闭哈希表-------开放地址法
开哈希只会和相同值发生冲突,而闭哈希除了与相同值发生冲突,还会与不同值发生冲突。所以,开哈希不受密度影响,而闭哈希受密度影响。
12、现有一完全的P2P共享协议,每次两个节点通讯后都能获取对方已经获取的全部信息,现在使得系统中每个节点都知道所有节点的文件信息,共17个节点,假设只能通过多次两个对等节点之间通讯的方式,则最少需要(30)次通讯。【记住】2n - 4次。