利用BitMap进行大数据排序去重

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));

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);

                }

            }

        }

    }

}

原文地址:https://www.cnblogs.com/z-sm/p/6238977.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,493评论 18 399
  • 文 | 夏九九 听过很多有关西藏的故事,却依旧想象不出那一番风景。因为能想象的,都是曾经所见的记忆拼凑,而无论如何...
    厦九九阅读 842评论 21 28
  • 人的一生,会面临几次选择呢,高考应该是我们面临的第一个重要的选择吧,嫁人应该是女人的第二个选择了,但是现...
    Flower燕子阅读 271评论 1 2
  • 春天的风带着哨声,从窗户缝用力的挤进来,让充满暖气的屋子有了一丝凉意。连风都那么努力的让人觉知,我要更加的努力活自...
    我坚持写简书阅读 271评论 0 0
  • 人生其实就是图个内在一致 人类所有的痛苦和矛盾都来源于内外的不一致,就是说内心想要的和真实拥有的不一样。而唯一解决...
    谢银环阅读 426评论 1 1