1、问题

问题提出

M(如10亿)个int整数,只有其中N个数重复出现过,读取到内存中并将重复的整数删除。

2、解决方案

问题分析

我们肯定会先想到在计算机内存中开辟M个int整型数据数组,来one bye one读取M个int类型数组, 然后在一一比对数值,最后将重复数据的去掉。当然这在处理小规模数据是可行的。

我们考虑大数据的情况:例如在java语言下,对10亿个int类型数据排重。

java中一个int类型在内存中占4byte。那么10亿个int类型数据共需要开辟10^9次方*4byte≈4GB的连续内存空间。以32位操作系统电脑为例,最大支持内存为4G,可用内存更是小于4G。所以上述方法在处理大数据时根本行不通。

思维转化

既然我们不能为所有 int 类型的数据开辟 int 类型数组,那么可以采取更小的数据类型来读取缓存 int 类型数据。考虑到计算机内部处理的数据都是 01 序列的bit,那么我们是否可以用 1bit 来表示一个 int 类型数据。

位映射的引出

使用较小的数据类型指代较大的数据类型。如上所说的问题,我们可以用1个 bit 来对应一个int 整数。假如对应的 int 类型的数据存在,就将其对应的 bit 赋值为1,否则,赋值为0(boolean类型)。java中 int 范围为 -2^31 到 2^31-1. 那么所有可能的数值组成的长度为2^32. 对应的 bit 长度也为 2^32. 那么可以用这样处理之后只需要开辟2^32 bit = 2^29 byte = 512M 大小的 内存空间 。显然,这样处理就能满足要求了,虽然对内存的消耗也不太小。

问题解决方案

首先定义如下图的int - byte 映射关系,当然,映射关系可以自定义。但前提要保证你的数组上下标不能越界。

但如上定义的bit[]数组显然在计算机中是不存在的,所我们需要将其转化为 java 中的一个基本数据类型存储。显然,byte[] 是最好的选择。

将其转化为byte[] 数组方案:

自定义的映射关系表,每个bit对应一个 int 数值,将 int 的最大值,最小值与数组的最大最小索引相对应。从上图可以看出来 int 数值与bit索引相差 2^31次方。当然,你也可以定义其他的映射关系,只是注意不要发生数组越界的情况。

bit[]索引:由于最大值可能是2^32,故用long接收: long bitIndex = num + (1l << 31);

byte[]索引:  int index = (int) (bitIndex / 8);  ,在字节byte[index]中的具体位置:  int innerIndex = (int) (bitIndex % 8);

更新值: dataBytes[index] = (byte) (dataBytes[index] | (1 << innerIndex));

3、代码

 import java.util.Random;

 /**
* 问题:M(如10亿)个int整数,只有其中N个数重复出现过,读取到内存中并将重复的整数删除。<br/>
* 使用位映射来进行海量数据的去重排序,原先一个元素用一个int现在只用一个bit, 内存占比4*8bit:1bit=32:1<br/>
* 亦可用java语言提供的BitSet,不过其指定bit index的参数为int类型,因此在此例中将输入数转为bit index时对于较大的数会越界<br><br/>
*/
public class BigDataSort { private static final int CAPACITY = 1_000_000;// 数据容量 public static void main(String[] args) { testMyFullBitMap(); } public static void testMyFullBitMap() {
MyFullBitMap ms = new MyFullBitMap(); byte[] bytes = null; Random random = new Random();
long startTime = System.currentTimeMillis();
for (int i = 0; i < CAPACITY; i++) {
int num = random.nextInt();
// System.out.println("读取了第 " + (i + 1) + "\t个数: " + num);
bytes = ms.setBit(num);
}
long endTime = System.currentTimeMillis();
System.out.printf("存入%d个数,用时%dms\n", CAPACITY, endTime - startTime); startTime = System.currentTimeMillis();
ms.output(bytes);
endTime = System.currentTimeMillis();
System.out.printf("取出%d个数,用时%dms\n", CAPACITY, endTime - startTime);
}
} class MyFullBitMap {
// 定义一个byte数组表示所有的int数据,一bit对应一个,共2^32b=2^29B=512MB
private byte[] dataBytes = new byte[1 << 29]; /**
* 读取数据,并将对应数数据的 到对应的bit中,并返回byte数组
*
* @param num
* 读取的数据
* @return byte数组 dataBytes
*/
public byte[] setBit(int num) { long bitIndex = num + (1l << 31); // 获取num数据对应bit数组(虚拟)的索引
int index = (int) (bitIndex / 8); // bit数组(虚拟)在byte数组中的索引
int innerIndex = (int) (bitIndex % 8); // bitIndex 在byte[]数组索引index 中的具体位置 // System.out.println("byte[" + index + "] 中的索引:" + innerIndex); dataBytes[index] = (byte) (dataBytes[index] | (1 << innerIndex));
return dataBytes;
} /**
* 输出数组中的数据
*
* @param bytes
* byte数组
*/
public void output(byte[] bytes) {
int count = 0;
for (int i = 0; i < bytes.length; i++) {
for (int j = 0; j < 8; j++) {
if (((bytes[i]) & (1 << j)) != 0) {
count++;
int number = (int) ((((long) i * 8 + j) - (1l << 31)));
// System.out.println("取出的第 " + count + "\t个数: " + number);
}
}
}
}
}

4、参考资料

http://yacare.iteye.com/blog/1969931

利用BitMap进行大数据排序去重的更多相关文章

  1. ASP.NET MVC + EF 利用存储过程读取大数据,1亿数据测试很OK

    看到本文的标题,相信你会忍不住进来看看! 没错,本文要讲的就是这个重量级的东西,这个不仅仅支持单表查询,更能支持连接查询, 加入一个表10W数据,另一个表也是10万数据,当你用linq建立一个连接查询 ...

  2. ASP.NET MVC + EF 利用存储过程读取大数据

    ASP.NET MVC + EF 利用存储过程读取大数据,1亿数据测试很OK 看到本文的标题,相信你会忍不住进来看看! 没错,本文要讲的就是这个重量级的东西,这个不仅仅支持单表查询,更能支持连接查询, ...

  3. Struts2 利用AJAX 导出大数据设置遮罩层

    Struts2 利用AJAX 导出大数据设置遮罩层 需求背景: 每次我们导出excel的时候 ,如果数据量很大,导出花费的时间会很长,页面却有没人任何反应,这个时候用户会认为系统有问题,要么关了页面, ...

  4. 大数据list去重

    MaxList模块主要是对Java集合大数据去重的相关介绍. 背景: 最近在项目中遇到了List集合中的数据要去重,大概一个2500万的数据,开始存储在List中,需要跟一个2万的List去去重. 直 ...

  5. 大数据排序算法:外部排序,bitmap算法;大数据去重算法:hash算法,bitmap算法

    外部排序算法相关:主要用到归并排序,堆排序,桶排序,重点是先分成不同的块,然后从每个块中找到最小值写入磁盘,分析过程可以看看http://blog.csdn.net/jeason29/article/ ...

  6. SQL Server 快速大数据排序方法

    SQL Server 中虽然有 ORDER BY NewID() 方法,但对于数据量比较大的结果集来说,排序那慢的可不是一星半点. 微软官方给了一种方案,https://msdn.microsoft. ...

  7. Winform .NET 利用NPOI导出大数据量的Excel

    前言:公司让做一个导出数据到Excel的小工具,要求是用户前端输入sql语句,点击导出按钮之后,将数据导出到Excel,界面如图所示:文件下端显示导出的进度 遇到的问题: 1.使用NPOI进行Exce ...

  8. SqlServer中的UNION操作符在合并数据时去重的原理以及UNION运算符查询结果默认排序的问题

    本文出处:http://www.cnblogs.com/wy123/p/7884986.html 周围又有人在讨论UNION和UNION ALL,对于UNION和UNION ALL,网上说的最多的就是 ...

  9. 第二篇:智能电网(Smart Grid)中的数据工程与大数据案例分析

    前言 上篇文章中讲到,在智能电网的控制与管理侧中,数据的分析和挖掘.可视化等工作属于核心环节.除此之外,二次侧中需要对数据进行采集,数据共享平台的搭建显然也涉及到数据的管理.那么在智能电网领域中,数据 ...

随机推荐

  1. iOS中空字符串报错

    *参考: http://www.ithao123.cn/content-8030945.html *参考: http://www.cnblogs.com/ziyi--caolu/p/4825633.h ...

  2. IOS 杂笔-11(实现在外部无法改变UIView的size)

    我想题目说的或许不是很清楚,那么现在我详细介绍一下这篇随笔内容. 在外部无法改变UIVIew控件的size. 这里说是UIView,但是事实上,是大多数控件而绝非仅UIView. 想要实现在外部无法改 ...

  3. 实现CheckBox的三种选中状态(全选、半选、不选)在GridView中模拟树形的功能

    度娘了很多帖子,只说三种状态要用图片替换来做,但没找到有用的例子,被逼自己写了一个 三方控件肯定是很多的,如jstree,可以直接用 由于公司的UDS限制,不能上传图片,只能文字说明了. 就是要在gr ...

  4. Oracle学习笔记八 表空间

    表空间 表空间是一个或多个数据文件的集合,所有的数据对象都存放在指定的表空间中,但主要存放的是表, 所以称作表空间 .   分区表 当表中的数据量不断增大,查询数据的速度就会变慢,应用程序的性能就会下 ...

  5. [Unity3D]巧妙利用父级子级实现Camera场景平面漫游

    本文系作者原创,转载请注明出处 入门级的笔者想了一上午才搞懂那个欧拉角的Camera旋转..=.= 在调试场景的时候,每次都本能的按下W想前进,但是这是不可能的(呵呵) 于是便心血来潮想顺便添加个Ke ...

  6. idea缓存

    昨天idea出现了一个奇怪的问题: 项目没有按我指定的配置运行,按cmd+:可以看输出.而是运行了配置包下的test环境的配置, 先一看,test环境被初始化为资源包并且在输出目录上, 先取消(fil ...

  7. L2-005. 集合相似度

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAzwAAAIRCAIAAAAA0S/lAAAgAElEQVR4nO3dzass133v//xPNTszDU

  8. TortoiseSvn的安装过程详解

    运行TortoiseSVN-1.6.6.17493-win32-svn-1.6.6.msi程序, 开始安装 点击Next, 下一步 选择 I accept 接受, 点击Next, 下一步 选择安装路径 ...

  9. webgl画个点

    function main(){ var canvas = document.getElementById("webgl"); var gl = getWebGLContext(c ...

  10. 1877: [SDOI2009]晨跑

    1877: [SDOI2009]晨跑 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 2007  Solved: 1085[Submit][Status][ ...