有一道流传广泛的面试题:

给你一台 4G 内存的机器,一组 20 亿个无序正整数,如何快速地判断一个正整数 N 是否在这组数字中?或者如何快速地对这组数据排重后排序?

让我们先算算 20 亿个整数会占用多大的内存空间,Java 的 int 类型占用 4 个字节,那么 20 亿 * 4 再换算成 G 大约是 7.5G,大于题目中 4G 内存的限制,无法一次性地放到内存中;

这时候有些伙伴会说:“把数据放到磁盘上,然后分批将数据读取到内存中就行查询”,但是这种方法会导致多次磁盘 IO,而且只能解决第一个查找的问题,排序就没有办法做到了。

01

BitMap 的概念

BitMap 能够很好地解决这个问题;它是用一个 Bit 位来标记某个元素对应的 Value, 而 Key 即是该元素,比如我们初始化一个类型为 bit、长度为 8 的数组,数组下标 0-7,数组中的内容 1 表示存在,0 表示不存在,那么:

00000001 下标为 0 的位置,对应值是1,那么表示 0;同理:

00000010 表示 1;

00000100 表示 2;

00001000 表示 3;

...

10000000 表示 7;

如果一组数据 {2,3,4,7} 放到同一个数组中的话,就是 10011100:

如果按照 int 数组存储,{2,3,4,7} 需要 4 * 4 * 8 个 bit 才能存储的数据,但是现在 BitMap 只需要 8 个 bit 就可以存储,很大地节省了存储空间,并且排重后的排序也变的非常简单了;如果用 byte 实现的话,只需要 1 个 byte 就可以(1 byte = 8 bits)。

如果增加了一个数字 10 呢,那么 1 个 byte 就不够了:

02

数据结构及初始化

我们可以得知,BitMap 的容量大小取决于最大的那个数值,比如要存储 {2,3,4,7,10}:

如果用 bit 数组实现(假如有的话),那么需要 10 + 1 个长度;

如果是用 byte 数组实现,那么需要 10/8 + 1 个长度;

如果是用 int 数组实现,那么就需要 10/32 + 1 个长度(1 个 int 等于 4 个 bytes,等于 32 个 bits);

明白了这点之后,一个简单的 BitMap 数据结构也就可以确定了:

public class BitMap {    //数据    private byte[] bits;     //最大值    private int max_value;    //容量    private int capacity;     /**     * 初始化     * @param capacity     */    public BitMap(int max_value){        this.max_value = max_value;        //1bit存储8个数据,存储最大值为 max_value 的数组需要 max_value/8+1 个 byte,除以8就是右移3位        this.capacity = (max_value >> 3 ) + 1;        bits = new byte[capacity];    }}

03

添加数据

添加数据,需要快速地定位到这个元素要存到整个数组中的哪个位置,这里有两个概念:

索引号 index:数据保存在整个数组的哪个下标中;

位置号 position:数据在这个下标元素的哪个位置;

比如 10 保存在 index = 1,position = 2(从 0 开始) 这个位置中,经推算可得:

index = N / 8position = N % 8

知道了 10 保存的位置之后,怎么把对应位置的数据更改成 1 呢?可以用“位或”运算。将 10 添加到 BitMap 中的完整步骤如下:

计算 index = 10/8 = 1 ;

计算 position = 10%8 = 2 ;

将 byte[1] 的数据与 0000100 做“位或”运算,其中 0000100 是通过对 1 左移 2 得到。

完整的代码如下:

public void add(int num){    //数据保存在整个数组的哪个下标中    int index = num / 8;    //数据在这个下标元素的哪个位置    int position = num % 8;     bits[index] |= 1<

04

判断数字是否存在

知道了如何判断数字的索引号和位置号之后,判断数字是否存在也就容易了,直接使用“位与”运算,代码如下:

public boolean contains(int num){  if(num > max_value){    return false;  }  //数据保存在整个数组的哪个下标中  int index = num / 8;  //数据在这个下标元素的哪个位置  int position = num % 8;  return (bits[index] & 1<

Java快速生成20亿数字_20 亿个数字在 4G 内存中如何去重排序:快来试一试 BitMap...相关推荐

  1. 20 亿个数字在 4G 内存中如何去重排序:快来试一试 BitMap

    作者 l 会点代码的大叔(CodeDaShu) 有一道流传广泛的面试题: 给你一台 4G 内存的机器,一组 20 亿个无序正整数,如何快速地判断一个正整数 N 是否在这组数字中?或者如何快速地对这组数 ...

  2. 对10亿个数据去重java_20 亿个数字在 4G 内存中如何去重排序:快来试一试 BitMap...

    有一道流传广泛的面试题: 给你一台 4G 内存的机器,一组 20 亿个无序正整数,如何快速地判断一个正整数 N 是否在这组数字中?或者如何快速地对这组数据排重后排序? 让我们先算算 20 亿个整数会占 ...

  3. Java快速生成20亿数字_关于内存:Java-打印10亿到20亿

    我想打印1000000至1999999999. 我以为这是一件容易的事,但是蚀告诉了我一些有关内存错误的信息. 我该怎么办? 我想要一个文本数据,其中所有数字都来自 将1000000000至19999 ...

  4. java 快速生成有残午餐_写出优质Java代码的4个技巧

    译者注:如果现在要求对你写的Java代码进行优化,那你会怎么做呢?作者在本文介绍了可以提高系统性能以及代码可读性的四种方法,如果你对此感兴趣,就让我们一起来看看吧.以下为译文. 本文我们将介绍一些有助 ...

  5. java快速生成数据库文档

    前言 在产品发布前夕,经常因为编写各类设计文档感到心碎,倒不是难,而是比较繁琐,举例来说,像编写数据库文档这种操作来说,对于新手,甚至很多有一定开发经验的同学来说,都觉得是一件费力得事情,下面推荐一个 ...

  6. Java黑皮书课后题第7章:**7.34(对字符串中的字符排序)使用以下方法头编写一个方法,返回一个排序好的字符串。编写一个测试程序,提示用户输入一个字符串,显示排序好的字符串

    **7.34(对字符串中的字符排序)使用以下方法头编写一个方法,返回一个排序好的字符串.编写一个测试程序,提示用户输入一个字符串,显示排序好的字符串 题目 题目描述 破题 代码 运行实例 题目 题目描 ...

  7. java实现生成指定位数随机字符串要求包含数字大小写字母三种类型字符

    今天接到一个初始密码生成的需求,要求生成的密码长度在8-16位,其中必须包含数字.大写字母.小写字母.平常都是使用hutool工具类进行字符处理,发现没有提供满足要求的方法,自己就根据现有的方法组装实 ...

  8. java流水号生成规则(固定位数,先通过数字生成,数字用完字母生成)

    今天来分享一个比较有意思的递增规则,开始也研究了一会,把高中学的等比等差都用上了,小喝了一杯茶,游荡一圈回来恍然大悟,所以说劳逸结合还是蛮重要的.下面进入正题: 我的规则是第一位作为头,后面所为流水号 ...

  9. java自动生成项目编号_java - Apache POI,在同一文档中创建项目符号点和编号列表 - 堆栈内存溢出...

    我试图用apache poi创建一个既包含圆点又包含编号列表的文档. 我想得到这样的结果. 名单: 清单1项目0 清单1项目1 清单1项目2 列表后的段落. 清单2: 清单2项目0 清单2项目1 清单 ...

最新文章

  1. 八十三、React简书项目:Styled-Components 与 Reset.css 的结合使用,完成Header布局
  2. uva10780 - Again Prime? No time
  3. 微盟合作,重磅推出全免费的H5专业营销平台,快速创建第一个H5活动(捷微H5)
  4. Python__名称空间与作用域
  5. Java 并发(入门梳理)
  6. angular代码规范_同样写代码,为何差距越来越大?
  7. socketio mysql_Golang + Socket.io
  8. Tapioca:linux上同gtalk语音通信
  9. strace ltrace使用
  10. 李开复、张亚勤、吴恩达…国际大咖给你讲解AI知识
  11. TFTP服务器的使用
  12. 微软应用商店_重新安装微软应用商店,并解决无法联网的问题
  13. Metasploit+Beef整合攻击——超详细
  14. c语言算法单循环球队比赛安排,单循环赛赛程安排算法的研究.doc
  15. HTML入门学习教程:简单网页制作
  16. 如果你不了解 python 的学习体系?来看看这篇博客吧 ,特邀嘴强擦哥做点评|Python技能树测评
  17. 如何用PDF编辑器将PDF文件拆分
  18. 数学三大核心领域概述:几何
  19. 计算机组成原理源码,计算机组成原理源码两位乘课程设计报告.docx
  20. 【打CF,学算法——四星级】CodeForces 86D Powerful array (莫队算法)

热门文章

  1. 六十八、SpringBoot连接MongoDB操作
  2. oracle子查询为游标结果集,这个SQL怎么破?select后的爬树子查询(connect by)变换
  3. 自训练 + 预训练 = 更好的自然语言理解模型
  4. Word Embedding Papers | 经典再读之fastText
  5. Byte Cup 2018机器学习大赛进入冲刺阶段,最全资料帮你快速上手!
  6. 投稿须知 | 让你的文字被很多很多很多人看到
  7. 【天池赛事】零基础入门语义分割-地表建筑物识别 Task3:网络模型结构发展
  8. ACM-ICPC 2018 徐州赛区网络预赛
  9. python传参怎么校验数字_python 多个参数不为空校验方法
  10. asterisk 配置 mysql_Asterisk的配置详解