Bitmap,今天我们来分析一下bitmap的实现原理以及它的使用场景。
一、使用场景:
1、对于大量数据(几千个数据的就不要在废话了),且无重复或者可以忽略重复的数字。为啥这里要强调无重复,因为在bitmap实现过程中再试无法处理。
2、用于查询新数字是存在在已知数据中。(如果用于全量打印之类的,循环性能上没有太大优势,内存空间上会有一定的优势)
3、查询速度能控制在1级别(what?难道连一次循环都不需要吗?是的,都不需要循环,都不需要循环,都不需要循环,重要的事情强调三次。)
二、实现原理
理论实现方案1:
结构 List<Integer> datas;
boolean contains(Integer i){ for循环获取}
结论:Integer 由一个 Integer是一个Class对象,(使用Java的银都知道,炒鸡占用内存啊,过儿……)
楼主:这得多少内存啊,容我仔细算算……
理论实现方案2:
结构 List<int> datas;
boolean contains(int i){for 循环获取}
结论:int 对 Integer 说:老弟,每个对象只需要4个字节即(32位)就够了,比你少了好多内存啊。
楼主:那你contains还要for循环,你这是O1,O1,O1 没听懂啊。(过儿……)
理论实现方案3:
结构 int [] datas;
boolean contains(int i){
if(datas[i] == 1) {return true;}
else{ return false;}
}
结论:利用下标的方式可以快速的获取数组中对应下标的值,如果为1 则表示存在,否则表示不存在。
缺点:一开始就需要初始化一个超级无敌大的数组
楼主:嗯,不错不错,给你点赞,查询不需要循环了。你比楼上的强多了。不过 一个int 4个字节 32位,如果最大值为 1000,000,000 那还是需要很多内存啊。
4000,000,000字节 = 3814MB ,这个……
理论实现方案4:
结构 int[] datas;
boolean contains(int i){ return "请参考具体实现……"}
楼主:你这个不是和上面的涨的一样吗,难道你想抄袭吗^_^
过儿:虽然长得像,可是内在不一样啊。请听我细细说来……
结论:一个int 4个字节 32位,方案3中,每个int只保存一个int值,我这个一个int 利用每一位进行保存一个int值,一个int可以保存32个值,内存只用1/32。厉害吧……
如果最大值为 1000,000,000 即 125,000,000字节 = 120MB
优点:利用每一个位进行保存一个数字,内存消耗可以大幅度的降低。
楼主:那你来实现一下。666~~~
三、Java 实现
public class BitMap { private int[] datas; private int m = 31; // 0-31 个位数 BitMap(int max) { int count = (max >> 5) + 1; datas = new int[count]; System.out.println("datas.length:"+datas.length); } // 添加 void add(int i) { int c = i >> 5; // 计算在那个datas下标中 int k = i & m; // 计算标记位k int d = datas[c]; d = d | (1 << k); // 标记k位 值为 1 datas[c] = d; } // 查询 boolean contains(int i) { int c = i >> 5; // 计算在按个datas下标中 int k = i & m; // 计算标记位k int d = datas[c]; int n = d >> k & 1; // 获取第K位的标记值 if (n == 1) { return true; } else { return false; } } public static void main(String[] args) { BitMap m = new BitMap(1000000000); m.add(39491); m.add(15157); m.add(26304); m.add(19857); m.add(17881); m.add(16593); m.add(478); m.add(8398); m.add(2011); // m.add(23134); // System.out.println("23134:"+m.contains(23134)); System.out.println("2011:"+m.contains(2011)); System.out.println("152:"+m.contains(152)); } }
运行结果:
datas.length:31250001
23134:true
2011:true
152:false
计算内存消耗:
System.gc(); long total = Runtime.getRuntime().totalMemory(); // byte long m1 = Runtime.getRuntime().freeMemory(); System.out.println("before:" + (total - m1)); BitMap m = new BitMap(1000000000); long total1 = Runtime.getRuntime().totalMemory(); long m2 = Runtime.getRuntime().freeMemory(); System.out.println("after:" + (total1 - m2)); long u= (total1 - m2) - (total - m1); // byte System.out.println("used:"+u/1024/1024+"M");
before:1958784
after:126958808
used:119M
简单实现了一下BitMap , 本例只用于学习使用。根据上面的代码可以看出,保存最大值为 1,000,000,000 的值,只需要 31250001个int 即 119MB