unordered系列关联式容器
- unordered_map
1、概念:
unordered_map是存储<key,value>键值对的关联式容器,允许通过key快速的索引到与其对应的value。
在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。在内部,unordered_map没有对<key, value>按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。unordered_map实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。 它的迭代器至少是前向迭代器。
2、利用哈希桶来实现unordered_map
我们在上一篇关于开散列的介绍中,已经实现了哈希桶的基本功能,但是所实现的并不能够封装unordered_map,因为unordered_map的存储结构是<key,value>的键值对,而我们所实现的只是存放普通的元素,而且unordered_map的一些接口(例如插入、删除)也与哈希桶的不同,因此,在这里我们将哈希桶的功能再完善一些
我们通过仿函数的方式按照key值获取到value,也就是增加一个模板类型KeyOfValue
让它实现通过key来获取value - unordered_set
unordered_set的实现只需要将unordered_map的实现改造一下即可(注意unordered_set没有通过下标来获取的运算符重载)
源代码(github):
https://github.com/wangbiy/C-3/commit/07794688cb909369130761528ed1d4fcff06ed14
海量数据面试题
- 1、哈希切割
给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?
如果我们按照传统的方式进行两个循环来统计,由于文件比较大,十分耗费时间,如果采用归并排序的方法也没有办法很好的解决这个问题,这时就要用到哈希切割,
(1)哈希切割就是将一个大文件,利用哈希原理将其分割成为若干个小文件(根据用户的限制估算被分割成文件的份数),然后获取每条IP地址,将IP地址(字符串)转换为整数(网络部分的库函数),然后将每个IP地址映射到相应文件中:IPINT%分割份数,此时相同的数据被分到同一个小文件中;然后统计IP地址的次数:即构建键值对unordered_map<IPINT,次数>,使用unordered_map来统计
(2)找到出现次数最多的IP地址
使用multimap<次数,IP地址>(底层是红黑树,已经根据次数排序好了)来查找
这样我们一共只遍历了一次,提高了性能,I/O次数降低
与上题条件相同,如何找到top K的IP?如何直接用Linux系统命令实现?
要建一个小堆—priority_queue(放的元素的类型是pair<次数,IP地址>),通过比较来找前k个次数最多的IP地址,即建立一个K个元素的小堆
用Linux命令实现:sort log_file | uniq -c | sort -nr k1,1 | head -10; - 2、哈希应用:位图
例如面试题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中
首先40亿整形数据大概估算是15G的大小,根本无法直接一次加载到内存中(一般计算机的内存是4G或者8G,还给系统内存分了2G的空间),所以如果采用遍历的方式来查找,需要分割这个数据,效率太低;
还有一种方法是进行排序,然后进行二分查找,但是这种方式还要加载数据,效率太低;
因此我们需要位图来解决这种问题
也就是数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。
先给一个例子:
如图: