【程序员代码面试指南】一 大数据

01 前言

这又是一个新的系列,为阅读「程序员代码面试指南」所做之笔记。尽量以一个小白能看懂的话讲。

每个问题分为几个部分:

  1. 题目
  2. 具体解决方案
  3. 思路重点
  4. 最后尝试用一句话来说完整个思路

只用2GB在20亿个整数中找到出现次数最多的数

题目

内存限制2GB,有一个包含20亿个全是32bit整数的大文件,找到出现次数最多的数。

具体方案

首先考虑所有数字都一样的情况,同一个数字的出现次数将达到20亿,我们使用一个32bit的整数足够记录。

假设我们使用哈希表,key为整数,value为出现次数,一个键值对共占用8Byte。由于当出现2亿个数的时候,内存占用为1.6G,在此我们假定每次能够比较的最大数字个数就为2亿个。

那么我们的下一步希望能够把大文件根据某种条件分散到n个文件中,每个文件中的数字个数最多为2亿。

考虑先根据哈希函数把整数分散到16个不同的文件中,这里假设我们的分类哈希函数足够秀,不会让其中某个文件的数字个数超过2亿。

这里需要一个 注意 点,就是不要混淆哈希函数跟哈希表的区别。

哈希函数实际上是对一堆信息的抽样,把任意的数据变成固定长度的信息。

灵魂拷问:

  • 为什么我们需要哈希函数?这是为了把不同大小的文件都缩减称为同等长度的哈希值,便于接下来的计算。
  • 为什么我们需要为什么上面说到哈希函数要足够 优秀?这是为了尽量保证每个数据算出来的哈希值要不一样。(极端情况下,所有文件的哈希值一样,肯定会被分到同一个文件)。
  • 用哈希值怎么分成十六个文件?用公式 $hash(data)$ % 16 就可以。

最后,我们分别统计16个文件中出现次数最多的数字(可以同一台计算机统计16次,或者直接分发到16台计算机中分别统计)。得到了每个文件中出现次数最多的数之后,我们再找出这16个数字中出现次数最多者,即可得到答案。

思路重点

如何把大文件分为若干个小文件,条件是什么。

一句话

把大文件中的数字按照某种条件分类成若干小文件,保证同一个数字只会出现在一个小文件中,再分别统计小文件中出现个数最多者。

bit map的应用

bit map,key是data,value是bit类型或者bit数组。

常用于检测大数据中某个数据是否存在。

找出数组中未出现的数

给定无序的海量数据数组长度为40亿,类型是unsigned int,范围是0 ~ 4 294 967 295。找出数组中,范围0 ~ 4 294 967 295内没出现过的数。

解决方案:

新建一个bit map,类型<unsigned int, bit>,遍历数组,只要数字出现过,就把对应的bit map位设置为1。

遍历完数组之后遍历bit map,找到所有value为0的条目,即为没有出现过的数字。

找出数组中出现过两次的数

只需要计算两次,所以只需要两个bit来记录出现的次数就够了。建立mapHashMap<unsigned int, bit*>。当数字出现了一次,把value设置为01,出现过两次,设置为10。

最后遍历bit map,找到所有value为10的key。

一致性哈希算法

服务器有时候需要把用户的id做哈希,然后分配到不同服务器做处理,来做 负载均衡 。如果采用上面提到的哈希函数分割法,每个用户确实可以顺利被分散到不同服务器上,但是如果增加或者减少了服务器的数量,所有用户的数据都需要全部重新分配( 因为 被除数变了,余数会发生变化)。

为了解决这个问题,我们避免采用对哈希值求余的方法来求得其应所在的服务器序号。

取而代之地,我们设想哈希值的范围,假设在[0, 232 - 1]内,我们把这个范围绕成一个环,然后把服务器均匀分布在上面。求得数据的哈希值之后,把数据交给环上顺时针的下一个服务器处理。

这样,当增加一个服务器的时候,只需要移动 一部分 数据到新服务器上。

岛问题

Buy Me A Coffee / 捐一杯咖啡的钱
分享这篇文章~
0%
//