目录
1:给⼀一个超过100G大小的文件,文件中存着IP地址, 设计算法找到出现次数最多的IP地址,如何找到top K的IP?
3:给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集
4:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
5:给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
7:与1题条件相同,如何直接用Linux系统命令实现找到top K的IP?
1:给⼀一个超过100G大小的文件,文件中存着IP地址, 设计算法找到出现次数最多的IP地址,如何找到top K的IP?
如果数据量比较小我们采用一个map或者unorder_map都能很快的处理,对于100G来说,我们只能采取哈希切分
什么是哈希切分?
100G文件我们无法处理,是1G文件我们能处理,100M文件我们能处理
- 哈希切分(映射)
将文件中所有的ip地址提取出来,对这个100G文件的ip地址进行处理将其分为1000个文件
哈希方法:对每个ip进行取模(ip%1000),这样将文件分成1000个100M的文件
因为是取模所以相同的ip会放在相同的文件中,不会有遗漏。 - 对每个切分的小文件进行统计
直接对小文件使用unorder_map<ip,size>进行统计,就能找出1000个出现次数最多的ip - 最后一次遍历
直接对1000个ip进行遍历,找出最多的那个
2:给定100亿个整数,设计算法找到只出现一次的整数
我们可以使用位图(bitmap)的方式,每一个数只需要两个bit(可以表示出现4次),一个字节存四个数字
100/4=25亿字节,所以需要2.5G的内存
如果还是超出限制,可以结合哈希切分!!!切分为10分,每次只需要250M
3:给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集
因为只需要找到交集,所以只需要用1bit就可以表示,一个字节可以表示8个数字,100/8=12.5亿字节,1.25G
因为两个文件所以需要2.5G
同样,可以哈希切分,分为10份,使用两个位图取统计,将位图结果按位与,就可以得到交集
4:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
使用位图和哈希切分统计出所有不超过2次的整数
5:给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
因为我们不确定数据类型,不能直接使用位图,所以直接使用布隆过滤器(BloomFilter)
同样经过先哈希切分,在布隆,每次两个布隆结果按位与记录
对于近似算法普通的布隆过滤器就能做到近似准确。
对于精确算法,我们将布隆进行扩展,一个数据映射n个位,这样虽然占用空间大,但是出现误判几率非常低
7:与1题条件相同,如何直接用Linux系统命令实现找到top K的IP?
第一步还是哈希切分,然后对 每一组文件使用awk sort uniq
awk:数据处理工具(文本切割)
sort:可以对输出结果排序,默认升序,-r转换为降序
uniq:可以过滤重复显示部分文件(读取输入文件,比较相邻两行) uniq -c 显示文件中出现的个数
8:给100亿整数,找出里面的中位数
找出中位数也就是找到第50亿个数和50亿01的平均值
先哈希切分,按照位数划分,假设从1开始100亿不重复,也就分为0~11这几个区别,
这时数据虽然无序,但是大小可以知道,在使用哈希切分判断中位数在哪一个文件中,数量会减少约九成
如果数据依然超出限制,因为数据都是一个位数的,直接对前最高位数字进行哈希,如前3位0~999,可分为1000个文件
足够加载到内存
处理海量数据的方法总结
1.Bloom filter
适用范围:实现数据字典,进行判重或者求集合的交集。
基本原理: 位数组+k个独立的hash函数,将hash函数对对应值的位数组 置1,查找时如果发现所有hash函数对应的位都是1,则说明存在。
2.Hashing
适用范围:快速查找,删除的基本数据结构,通常总数据量可以放入内存。
基本原理:
hsah函数的选择:
碰撞处理:拉链法,开放地址法
3.bit-map
适用范围:可进行数据的快速查找,判重,删除(一般来说数据范围是int的10倍以下)
4.堆
使用范围:找出海量数据的前k个数,并且数据总量n比较小,堆可以放入内存。
基本原理:最大堆求前n小,最小堆求前n大,
5.trie树
适用范围:数据量大,重复多,但是数据中类小,可以放入内存
布隆过滤器:
直观的说,bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中。
和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中。
算法:
1. 首先需要k个hash函数,每个函数可以把key散列成为1个整数
2. 初始化时,需要一个长度为n比特的数组,每个比特位初始化为0
3. 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
4. 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。
优点:不需要存储key,节省空间
缺点:
1. 算法判断key在集合中时,有一定的概率key其实不在集合中
2. 无法删除
Trie树
Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
它有3个基本性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符。
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
每个节点的所有子节点包含的字符都不相同。
哈希树
哈希树的理论基础:
【质数分辨定理】
简单地说就是:n个不同的质数可以“分辨”的连续整数。
“分辨”就是指这些连续的整数不可能有完全相同的余数序列。
哈希树:
第一层有两个子节点,下面每层依次3,5,11,13,17连续的质
一般不会超过10个数,连续10个质数就可以分辨大约M(10) =2*3*5*7*11*13*17*19*23*29= 6464693230 个数
哈希树的节点查找过程和节点插入过程类似,就是对关键字用质数序列取余,根据余数确定下一节点的分叉路径,直到找到目标节点。
哈希树的节点删除过程也很简单,哈希树在删除的时候,并不做任何结构调整。
只是先查到到要删除的节点,然后把此节点的“占位标记”置为false即可(即表示此节点为空节点,但并不进行物理删除)。
优点和缺点
优点:结构简单 注意hash树是单向增加的,即使删除也不会减少hash树的结构
查找迅速 对于int的数据 最多查找10次
结构不变 即使删除属于也不会改变结构,
缺点:非排序性 就是数据时没有顺序的