待续
Hash Table:
1. 什么是?
2. 什么问题用?
3. 怎么用?
4. 实际应用?
5. 实际代码?
6. 思考问题?
1. 什么是?
参考:
http://www.cnblogs.com/vamei/archive/2013/03/24/2970339.html
哈希表(hash table)是从一个集合A到另一个集合B的映射(mapping)。
上述对应过程称为hashing。A中元素a对应B中元素b,a被称为键值(key),b被称为a的hash值(hash value)。
哈希表的核心是一个哈希函数(hash function),这个函数规定了集合A中的元素如何对应到集合B中的元素。
4. 实际应用?
参考:
http://www.cnblogs.com/vamei/archive/2013/03/24/2970339.html
Ethernet中的FCS:参看小喇叭开始广播 (以太网与WiFi协议)
IP协议中的checksum:参看我尽力 (IP协议详解)
git中的hash值:参看版本管理三国志
登陆密码:
使用MD5、SHA或者其他算法作为hash函数:密码字符串---》hash值
效果:所使用的hash函数有很好的单向性:很难从hash值去推测键值
hash函数:搜索对象---》存储位置
效果:一次hash,将对象所在位置找到
过程:
以人名(字符串)为键值,以数组下标为hash值。每个数组元素中存储有一个指针,指向记录 (有人名和电话号码)。
在搜索"Vamei"的记录时,可以经过hash,得到hash值498,再直接读取records[498],就可以读取记录了。
数组records的大小为HASHSIZE,HASHSIZE被选择为质数,以便hash值能更加均匀的分布。
Python: Hashing
a = 'Obama'
value = 0
for i in a:
value+=ord(i)
print ('Hash value of %r is %r') %(a,value)
<p class="p1"><span class="s1">Hash value of 'Obama' is 480</span></p>
比较:
如果不采用hash,而只是在一个数组中搜索的话,我们需要依次访问每个记录,直到找到目标记录,算法复杂度为n。
利用键值和hash函数,来选择适当的下标进行搜索。在没有hash碰撞的前提下,我们只需要选择一次,就可以保证该下标指向的元素是我们想要的元素。
由于数组可以根据数组下标进行随机存取(random access,算法复杂度为1),所以搜索操作将取决于hash函数的复杂程度。
6. 思考问题?
hash冲突:上面的hash函数中,"Obama"和"Oaamb"有相同的hash值
一个方案是将发生冲突的记录用链表储存起来,让hash值指向该链表,这叫做open hashing:
先根据hash值找到链表,再根据key值遍历搜索链表,直到找到记录。
open hashing需要使用指针。我们有时候想要避免使用指针,以保持随机存储的优势,所以采用closed hashing的方式来解决冲突。
将冲突记录放在数组中依然闲置的位置,
比如图中Obama被插入后,随后的Oaamb也被hash到480位置。但由于480被占据,Oaamb探测到下一个闲置位置(通过将hash值加1),并记录。
closed hashing的关键在如何探测下一个位置。
在第i次的时候,我们应该探测POSITION(i)=(h(x) + f(i)) % HASHSIZE的位置。
上面将hash值加1的方式,就相当于设定f(i) = 1。当我们在搜索的时候,就可以利用POSITION(i),依次探测记录可能出现的位置,直到找到记录。
f(i)的选择会带来不同的结果
如果数组比较满,那么closed hashing需要进行许多次探测才能找到空位。这样将大大减小插入和搜索的效率。
这种情况下,需要增大HASHSIZE,并将原来的记录放入到新的比较大的数组中。这样的操作称为rehashing。
其他参考:
http://blog.csdn.net/liufei_learning/article/details/19220391
kernel 中的hash table的实现 http://blog.csdn.net/zdl1016/article/details/8882083
http://www.importnew.com/16138.html
从头到尾彻底解析Hash表算法 http://kb.cnblogs.com/page/189480/