在计算机中有两种情况称之为海量
- [ 空间 ] 无法一次性装入内存
- [ 时间 ] 较短时间内无法迅速解决
问题的解决方法自然也要从 [ 时间 ] 和 [ 空间 ] 两个角度考虑。
- 针对时间:我们可以采用 算法 + 数据结构
Bloom filter
Hash
Bit-map
堆
数据库
倒排索引
Trie树 - 针对空间:无非就是分而治之、大事化小、小事化了。
1、Hash:拆分大文件为多个小文件
比如现在有10亿条数据,我们创建 10 个空文件 ,遍历这 10 亿个关键词,并且通过某个哈希算法对其求哈希值,然后哈希值%10
,得到的结果就是这个搜索关键词应该被分到的文件编号。
2、堆
求TOPK
小根堆求最大TOPK
大根堆求最小TOPK
遍历数组需要 O(n)
的时间复杂度,一次堆化操作需要 O(logK)
的时间复杂度,所以最坏情况下,n 个元素都入堆一次,所以时间复杂度就是 O(nlogK)
。
优先队列
假设我们有 100 个小文件,每个文件中存储的都是有序
的字符串。我们希望将这些 100 个小文件合并成一个有序
的大文件。这里就会用到优先级队列
。
3、位图bitmap:是否出现/去重
位图适用于大规模数据下判断某个数据是否存在。
位图实现原理:
一个int占4字节,一个字节占8bit,所以一个int=32bit
我们申请一个int类型的数组,每个位置可以用来记录32种状态,相当于将所需内存压缩了32倍
举例:现在文件中的最大数字为160,那么就申请160/32=5个长度的int数组即可
当我要判断136是否存在时,只需要判断对应位置是否不为0即可。
int main(){
int a[5]={0};
a[3]|= 1<<25;
cout<<((a[3]&1<<25)!=0)<<endl;
}
c++11提供了bitset方便进行位运算
4、布隆过滤器:从n里面筛除m个
对于网页黑名单系统、垃圾邮件过滤系统、爬虫的网址判重系统等
对系统容忍一定程度的失误率, 并且对空间要求比较严格
那么就适合使用布隆过滤器。
布隆过滤器的优势就在于使用很少的空间就可以将准确率做到很高的程度。
布隆过滤器判断某个数是否存在,说它存在可能判断错其实不存在,但是说它不存在就一定不存在
布隆过滤器如何工作的?
利用bitmap和hash函数
假设有一个长度为m的bitarray数组
再假设一共有k个哈希函数, 这些函数的输出域S 都>=m, 并且这些哈希函数都足够优秀, 彼此之间也完全独立。 那么对同一个输入对象。经过k个哈希函数算出来的结果也是独立的,可能相同,也可能不同,但彼此独立。对算出来的每一个结果都对m取余 ( %m ), 然后在bitarray上把相应的位置设置为1(涂黑), 如图:
我们把bit类型的数组记为bitMap。 至此, 一个输入对象对bitMap的影响过程就结束了,也就是bitMap中的一些位置会被涂黑。 接下来按照该方法处理所有的输入对象,每个对象都可能把bitMap中的一些白位置涂黑,也可能遇到己经涂黑的位置,遇到已经涂黑的位置让其继续为黑即可。 处理完所有的输入对象后,可能bitMap中己经有相当多的位置被涂黑。 至此, 一个布隆过滤器生成完毕, 这个布隆过滤器代表之前所有输入对象组成的集合
那么在检查阶段时, 如何检查某一个对象是否是之前的某一个输入对象呢?
假设一个对象为a,想检查它是否是之前的输入对象,就把a通过k个哈希函数算出k个值,然后把 k个值取余(%m), 就得到在[0,m-1]范围上的k个值。 接下来在bitMap上看这些位置是不是都为黑。
- 如果有一个不为黑, 说明a 一定不在这个集合里。
- 如果都为黑, 虽然不是一定,但就认为a 在这个集合里。