zoukankan      html  css  js  c++  java
  • 大数据处理之bitmap (java实现)

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

     

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

                

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

     

    java中一个 int 类型在内存中占4 byte。那么10亿个int类型数据共需要开辟10 ^ 9次方 *4 byte ≈ 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次方。当然,你也可以定义其他的映射关系,只是注意不要发生数组越界的情况。由于最大值可能是2^32,故用long接收。

    long bitIndex = num + (1l << 31);

     

    计算在转化为byte[]数组的索引,由于上面定义的bitIndex 索引是非负数,故无需引入位运算去符号。

     int index = (int) (bitIndex / 8); 

     

    计算bitIndex 在byte[]数组索引index 中的具体位置。

     int innerIndex = (int) (bitIndex % 8);

     

    引入位运算将byte[]数组索引index 的各个位按权值相加

    dataBytes[index] = (byte) (dataBytes[index] | (1 << innerIndex));

     

    这样就解决了整个大数据读取排重的问题。

     

    那么怎么将其读取出来呢?怎么对数据进行排序?

     

    那就只需要按照byte[]数组进行一一对应到 int 类型数据上即可。

    以下代码升序输出为例。

     

    遍历数组,采取与之前映射关系的逆运算来还原数据。

     

     for (int i = 0; i < bytes.length; i++) {

                for (int j = 0; j < 8; j++) {

                    if (!(((bytes[i]) & (1 << j)) == 0)) {

                        int number = (int) ((((long) i * 8 + j) - (1l << 31)));

                    }

                }

            } 

     }

     

     

    由于编译软件默认设置的JVM内存是128—400M左右,测试此程序明显是不够的,所以需要调节一下分配给JVM的内存。否则,不管怎样运行,都会出现Exception in thread "main" java.lang.OutOfMemoryError: Java heap space...

     

    eclipse:选择run->run configuration->arguments,输入-Xms256M -Xmx1024M(-Xms代表jvm启动时分配的内存大小,-Xmx代表可最大分配多少内存)

    Intellij IDEA修改安装目录/IntelliJ IDEA 7.0/bin下idea.exe.vmoption文件 

        -Xms256M 
        -Xmx1024M 
      
        

     

     

    源代码:

     

    Java代码  收藏代码
    1. package com.MassSort20131103;  
    2.   
    3. import java.util.Random;  
    4.   
    5.   
    6. /** 
    7.  * Created with IntelliJ IDEA. 
    8.  * User: YangKang 
    9.  * Date: 13-11-3 
    10.  * Time:上午11:32 
    11.  * To change this template use File | Settings | File Templates. 
    12.  */  
    13. public class BigDataSort {  
    14.   
    15.     private static final int CAPACITY = 1 000 000 000;//数据容量  
    16.   
    17.     // 定义一个byte数组缓存所有的数据  
    18.     private byte[] dataBytes = new byte[1 << 29];  
    19.   
    20.     public static void main(String[] args) {  
    21.         BigDataSort ms = new BigDataSort();  
    22.   
    23.         byte[] bytes = null;  
    24.   
    25.         Random random = new Random();  
    26.         for (int i = 0; i < CAPACITY; i++) {  
    27.             int num = random.nextInt();  
    28.             System.out.println("读取了第 " + (i + 1) + " 个数: " + num);  
    29.             bytes = ms.splitBigData(num);  
    30.         }  
    31.         System.out.println("");  
    32.         ms.output(bytes);  
    33.     }  
    34.   
    35.   
    36.     /** 
    37.      * 读取数据,并将对应数数据的 到对应的bit中,并返回byte数组 
    38.      * @param num 读取的数据 
    39.      * @return byte数组  dataBytes 
    40.      */  
    41.     private byte[] splitBigData(int num) {  
    42.   
    43.         long bitIndex = num + (1l << 31);         //获取num数据对应bit数组(虚拟)的索引  
    44.         int index = (int) (bitIndex / 8);         //bit数组(虚拟)在byte数组中的索引  
    45.         int innerIndex = (int) (bitIndex % 8);    //bitIndex 在byte[]数组索引index 中的具体位置  
    46.   
    47.         System.out.println("byte[" + index + "] 中的索引:" + innerIndex);  
    48.   
    49.         dataBytes[index] = (byte) (dataBytes[index] | (1 << innerIndex));  
    50.         return dataBytes;  
    51.     }  
    52.   
    53.     /** 
    54.      * 输出数组中的数据 
    55.      * @param bytes byte数组 
    56.      */  
    57.     private void output(byte[] bytes) {  
    58.         int count = 0;  
    59.         for (int i = 0; i < bytes.length; i++) {  
    60.             for (int j = 0; j < 8; j++) {  
    61.                 if (!(((bytes[i]) & (1 << j)) == 0)) {  
    62.                     count++;  
    63.                     int number = (int) ((((long) i * 8 + j) - (1l << 31)));  
    64.                     System.out.println("取出的第  " + count + " 个数: " +  number);  
    65.                 }  
    66.             }  
    67.         }  
    68.     }  
    69. }  


    原文链接:http://yacare.iteye.com/blog/1969931

  • 相关阅读:
    剑指 Offer 22. 链表中倒数第k个节点(简单)
    剑指 Offer 18. 删除链表的节点(简单)
    Proxy error: Could not proxy request
    剑指 Offer 63. 股票的最大利润(中等)
    剑指 Offer 47. 礼物的最大价值(中等)
    剑指 Offer 42. 连续子数组的最大和(简单)
    oracle 常用函数之 字符函数
    oracle 常用函数之 日期函数
    oracle 常用函数之聚合函数
    jdbc
  • 原文地址:https://www.cnblogs.com/a3192048/p/12241340.html
Copyright © 2011-2022 走看看