Java 位映射实现数据查重

1、位图法介绍

位图的基本概念是用一个位(bit)来标记某个数据的存放状态,由于采用了位为单位来存放数据,所以节省了大量的空间。举个具体的例子,在Java中一般一个int数字要占用32位,如果能用一位就表示这个数,就可以缩减大量的存储空间。一般把这种方法称为位图法,即Bitmap。

位图法比较适合于判断是否存在这样的问题,元素的状态比较少,元素的个数比较多的情况之下。那么具体咋么做呢,这样,非常简单明了就是,2.5亿个整数里面,我维护一个长度等于最大整数值得字符串,每个整数是否存在我就在该整数对应的位置置为1,比如,有{2, 4, 5, 6, 67, 5}这么几个整数,我维护一个 00…0000 67位的字符串。但是,如果你不知道整数的最大值,你至少需要一个长度2^ 32的字符串,因为整数的最大值就是2^ 32,(int占4个字节,因此是32位),那这就最少是512M内存,从char的长度算内存会算吧,直接、最大整数/8*2^20 就是M的单位。那这么说来就可以理解位图法了。

位图映射规则

位图映射的规则就是 为一长串的二进制数的对应位标记为1就行了,其优点就是不用像存于hashmap的key那样耗内存,比如我们存储的是数组中的第一二个字节:

1000000000001000 

表示在位图中存储的是16 与 4 这两个数

2、BitSet

正因为位图运算在空间方面的优越性,很多语言都有直接对它的支持。如在C++的STL库中就有一个bitset容器。而在Java中,在java.util包下也有一个BitSet类用来实现位图运算。此类实现了一个按需增长的位向量。BitSet的每一位都由一个boolean值来表示。用非负的整数将BitSet的位编入索引,可以对每个编入索引的位进行测试、设置或者清除。通过逻辑与、逻辑或和逻辑异或操作,可以使用一个BitSet修改另一个BitSet的内容。

BitSet底层实现是通过一个long数组来保存数据的,也就是说它增长的最小单位是一个long所占的逻辑位,即64位。

下面用代码来演示用位图法来实现查找数组中的重复数据:

package com.xwt1208bitmap;


//查找重复并排序
import java.util.Arrays;
import java.util.Random;

/**
 * 
 * @author xwt
 *
 */

public class Test{
  int ARRNUM = 10;
  int LEN_INT = 32;
  int mmax = 1008;
  int mmin = 1000;
  int N = mmax - mmin + 1;

  public static void main(String args[]) {
       new Test().findDuplicate(); 
       
  }


  public void findDuplicate() {
      int[] array = getArray(ARRNUM);
      int[] bitArray = setBit(array);
      printBitArray(bitArray);
  }

  public void printBitArray(int[] bitArray) {
      int count = 0;
      System.out.print("有重复的数据为:");
      for (int i = 0; i < N; i++) {
          if (getBit(bitArray, i) != 0) {
              count++;
              System.out.print(i + mmin + ", ");
          }
      }
      System.out.println();
      System.out.println("找出有重复的数据并排序后的数组大小为:" + count);
  }

  public int getBit(int[] bitArray, int k) {// 1右移 k % 32位 与上 数组下标为 k/32 位置的值
      return bitArray[k / LEN_INT] & (1 << (k % LEN_INT));
  }

  public int[] setBit(int[] array) {// 首先取得数组位置下标 i/32, 然后 或上 在该位置int类型数值的bit位:i % 32
                                      
      int m = array.length;
      int bit_arr_len = N / LEN_INT + 1;
      int[] bitArray = new int[bit_arr_len];
      int[] bitArray1 = new int[bit_arr_len];
      for (int i = 0; i < m; i++) {
          int num = array[i] - mmin;
          
          if((bitArray[num/LEN_INT] & (1 << (num % LEN_INT)))!=0) {
        	  bitArray1[num/LEN_INT] |= (1 << (num % LEN_INT));
          }
          bitArray[num/LEN_INT] |= (1 << (num % LEN_INT));
      }
     
      
      return bitArray1;
  }

  public int[] getArray(int ARRNUM) {

      int array[] = new int[ARRNUM];
      System.out.println("原始数组大小:" + ARRNUM);
      Random r = new Random();
      for (int i = 0; i < ARRNUM; i++) {
          array[i] = r.nextInt(N) + mmin;
      }

      System.out.println(Arrays.toString(array));
      return array;
  }
}

某一次运行后的输出为:

原始数组大小:10
[1003, 1005, 1003, 1006, 1001, 1001, 1007, 1003, 1000, 1006]
有重复的数据为:1001, 1003, 1006, 
找出有重复的数据并排序后的数组大小为:3
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值