面试中好多都问到hash,特此总结备注。
首先感谢july这篇博客的讲解,看完之后就基本掌握七八了:http://blog.csdn.net/v_july_v/article/details/6256463
哈希表
概念:也叫做散列表,即通过一个散列函数将关键码(Key)映射到散列表中的具体某一个位置,在该位置记下Key对应的Value值。
好处:查找的速度从O(n)的遍历变为了O(1)。
做法:把Key通过一个哈希函数转换为一个整数,然后将整数对数组长度取余,结果即为数组下标,将Value存储在该数字为下标的数组空间中。
应用:
(1)问题:统计一个超大文本中每个单词出现的频次,但数据量太大无法一次装入内存。
解决:可以将文本分解为多个,再将每个小文本交由一台机器来处理,最后将结果统一。这样问题就转换为,如何将这个大文本分割为若干小文本?
或许你觉得将文本按一定大小等量分为若干份即可,但是这样存在一个问题,每个小文本中单词的多样性将导致最后统一合并时工作很难进行;
或许你可以想到可以按照单词的首字母分割,比如讲以a开头的交由一台机器,以b开头的交由另一台等等以此类推,但是这样的话每个机器分到的文本大小就有很 大 的差别,比如以z开头的单词肯定要远远少于以s开头的单词。
这样问题就更清晰了:如何找到一个好的划分,让大文本中的单词尽量均匀分给每一个小文本。
答案就是hash:将大文本中的每个单词都hash到每一个小文本中。
(2)问题:Top-K问题,要统计最热门的Query,首先需要统计每个Query出现的次数,然后找出前10
解决:采用HashTable,其中Key:Query字串,Value:该Query出现的次数。如果改字串不再table中,那么假如该字串,并将value设为1;如果在table中,value++。
后续用堆找出Top-K。具体的算法见July的博客,其中还有排序等方法来求解该问题的算法。
散列方法:除数散列法,平方散列法,斐波那契散列法...
冲突探测:
(1)MPQ算法, 采用3种不同的哈希函数:一个用于下标,另两个用于验证。即当用第一个hash找到该位置下位置不为空,则继续检查另两个计算的哈希值是否相同,如果不相同继续下移一个位置检查(因为采用顺延的方法解决冲突)。
(2)布隆过滤器:使用多个hash,映射到一个BitArray中,如果它们有一个说元素不在集合中,那肯定就不再;如果它们都说在,虽然有一定可能性它们都在说谎,不过这种事情的概率比较低。具体的算法可参考http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html。
哈希函数个数k、位数组大小m、加入的字符串数量n的关系可以参考文献1。该文献证明了对于给定的m、n,当 k = ln(2)* m/n 时出错的概率是最小的。
冲突解决:
链表、顺延......