一、哈希函数
又称散列函数,哈希函数的输入域可以使非常大的范围,但输出域是固定的范围,假设为s。
哈希函数的性质:
1.典型的哈希函数拥有无限的输入值域;
2.输入值相同时返回值一样,但是输入值不同时返回值也有可能一样,也可能不一样;
3.不同的输入得到的哈希值会均匀的分布在s域上。(重要特性)
1.2都是属于哈希函数的性质,而3则属于哈希函数的性能关键的评价,一个号的哈希函数实现就应该做到所有的哈希值都平均的分布在s域上。
还有一点就是对于类似的输入,优秀的哈希函数求出的哈希值会有很大的差别。
PS
(1)对于大数据的题,一般都会采用分而治之的方法,通过hash哈数将大的任务化分为小的任务。
(2)场用来解决大数据的有使用hash函数或者是bitmap或者是hashmap等等解决的。
(3)大数据问题的解决不在解决方式而在,通讯,时间空间计算等。
题二:
将10亿个IpV4地址排序
解析:一个IPV4地址占内存32位,二IPV4的总个数为2的32次方。
所以我们的思路是将每一个IPV4的整数化为他对应的整数,其次我们在创建一个长度为2的32次方的数组arr。然后我们再遍历这十亿个整数将这些整数减一后当做arr中的下标。如果某个下标出现我们就将arr中该下标的位置设为1,一直到十亿个整数遍历完,之后我们只要遍历arr,找到里面元素值为1的下标,将下标加一后转化为iPV4的格式就实现了iP地址的排序。
在分析一下这道题解法的优势,创建一个arr数组总共占用内存128M,其中时间复杂度就是一次遍历十亿个数的时间和遍历arr的时间,比普通的排序方法好很多很多。
其实类似的为题还有电话号码的排序呀!等等。
题三:
中国有13亿人,每个人都有年龄,请将中国人的年龄排序。
其实这道题特别简单,我们可以默认一般人的岁数最大为150(现代人肯定没有大于150岁的)
我们就创建一个长度为151的数组,如果某个人的岁数是该数组的某个下标值,那么就将该下标下的值加一(默认所有人的岁数都是取整)。(其实就是一个计数排序的思想)
题四:
某个文件中40亿个32位无符号整数,现在要你找出没有出现在这40个数中的一个。只有8M的额外空间
分析:
无符号整数一共有2^32个,如果我们使用2^32的bitmap的话就需要使用512M的空间,而我们只有8M的空间。
所以解决的方法是,我们先将0-(2^32-1)划分为64个区间(512/8)。然后每个区间的长度就是2^32/64,我们在遍历这个40亿个数如果他出现在某个区间就将它出现区间的元素个数加一,然后我们找到这些区间中个数不足2^32/64的,然后我们在这个区间上去创建一个bitmap长度为2^32/64刚好8M空间,我们再去遍历这四十亿个数,然后如果某个数出现在该区间上就将bitmap上对应的下标值变为1,最后我们再去bitmap中第一个为0的下标,在通过这个下标去找到他的对应整数即可。
题五:
某个大文件中有20亿个数,统计出次数出现最多的那一种数之一,但是额外空间就只有2G。
遇到这个问题首先想到的是用hash表做词频统计。
那加入我们使用hash表的话:
hash表的key和value都是四字节。加入最坏的情况所有的数都不相同就需要80亿字节(约16G),可定是超出内存了的。
所以我们的解决办法还是分而治之。
首先我们将这些数分到16个小文件中,然后我们在每一个小文件中使用hash表做词频统计。分别统计出每个小文件中最多的那个数字以后再综合16个即可求出最多的出现次数的那个数
题六:百亿级搜索词汇
某个做搜索引擎 的公司,他们每天的搜索量能够达到100亿条搜索词汇,他们现在想在这100亿条搜索量中统计出出现率最高的一百个词汇(这些词汇都都存在了硬盘上了)。
我们的解决办法还是分治的思想。
首先我们可以利用hash函数将这一百亿条词汇分流到n太机器上面去,具体n等于多少还需要看机器实际的硬件参数来决定,我们分到这n个机器上以后又因为这些机器的内存有又都是有限的,所以我们可以将每个机器上的词汇再分到m个文件中。然后我们可以利用每个小文件中的数建立top100小根堆。每个文件处理完以后我们可以利用外排序或者是小根堆再次将每个小文件合并,同样的思想还可以将每个机器的合并最终就能合并出top100。
题七:一致性hash算法
工程师尝试用服务器集群来设计和实现数据缓存,一下是常见的策略,1无论是添加、查询、还是删除都是先将某个数据的id通过hash函数计算出一个hash值记为key,如果当前有N太服务器,那么用key%N就是这个数据所属的机器编号,无论是添加查询、删除都只在这台机器的上进行,咋一看这个方法好像没什么问题。请你提出改良方法。
咋一看这个方法好像没什么问题但是如果我们在添加或者是删除机器的时候就需要将重新进行取模运算,就需要就大量的数据在机器之间交换,所以这是一个很大的问题,解决方法就是使用“一致性hash算法”;
下面是一致性hash算法实现:
假设我们通过hash函数计算的hash中为32位整数,那么我们将这写整数从0到2^32-1首位相连,最终构成一个环,然后每个机器就放在环上,每次我们在计算出某个数聚的hash值以后就将它存在它顺时针的第一个机器上(每个机器在环上也有一个编号)
那么我们在添加一台机器A的时候z只需要将范围a中的数据从X中移到A中即可。
同样我们在删除一个机器A的时候只需要将范围a中的数据移到X中即可。
布隆过滤器:
定义:布隆过滤器可以精确的表示一个集合课精确的判断某一个元素是否属于此集合中精确的程度有用户的具体设计而定。但是想要做到的100%的精确率是不可能的。
虽然存在一定的误差,但是布隆过滤器器的优势在于利用少量的空间就可以做到很高的精确度。
布隆过滤器由k个hash函数(彼此完全独立),这些hash函数的输出域都是大于等于m的、m长度的bitarray。每个URl经过k个hash函数算出来的结果都是相互独立的,我们将每一个hash过后的值进行对m取模,然后得到一个值,将这个值作为bitarray中的下标,将对应下标的值设为1这个过程叫做布隆过滤器涂黑。
以下我们分析一下实例:
假设我们手上一批网页黑名单, 我们还有10亿个其他的URL请你找出这10亿个URL中的黑名单URL(我们在查找的过程中允许万分之一的失误率)。
思路就是:我们先用黑名单URL将布隆过滤器涂黑,然后在遍历每一个URL,用布隆过滤器去检查每一个URL在检查的过程中如果某个URL的k个hash值都被涂黑了代表,这个URL就是一个黑名单URL,如果其中有一个URL没有被涂黑代表这不是一个黑名单URL。
布隆过滤器的实现思路很简单,主要是我们需要知道bitarray的长度,需要多少个hash函数。
这些值都可以用已有数据中数和允许失误率算出来下面是公式:
设样本大小为n,bitarray长度为m、失误率为p。
单个样本的大小不影响布隆过滤器的大小,只影响hash函数实现细节。
m=(n*lnp)/(ln2)^2
最后求得的m值需要向上取整
k=ln2*(m/n)