jdk 源码分析(6)java BitSet结构
2017-08-02 21:39
736 查看
虽然bitSet取名有set,但确实不是Set的子集
本来想去找个图片,结果没找到,简单点。
如果有一个Set 里面存放了(整数)1,3,4,5,23,23,12,65这些数,如果直接存储需要8×32位 ;
如果采用位图,只需要用两个long整型串联。
一个位置表示这个数的存储。
比如1,第一个long的第2个位为1
比如4,第一个long的第2个位为1
比如65,第二个long的第2个位为1
所以数据存储时x:
long []value
value[x/64] = value [x/64] |
1L<<x
value[x/64] 表示数据将放在第几个long 中, 因为1l 是以64为周期循环移动,会得到具体的存放位置。
x/64 = x>>6
查看Java 的bitSet的源码:
实际存放的位置
初始长度为1
添加数据。添加数据会
throw new IndexOutOfBoundsException("bitIndex < 0: "+ bitIndex);
这里扩展成倍数扩展,没有优化
其他几个重要操作:add 直接是long的& ,比单个位操作要快,
其他还有xor,or 等。
不管怎么,bitset 初步解决了数据存储问题。但是还有很多优化问题,
比如:1)需要存储的数据只是一个1亿,那么也需要用1亿/64个long表示。
再比如 连续的 1,2,3,4,5,6 。。。1000.. 也需要存储1000/64个整数。
对于第一种 直接用ArrayList 比 bitset 节约空间。
第二种,采用run of length 比较好。比如开始位 1,重复999 . 所以只需要存储,1,999 就可以了,如果还有,
2000-4000 , 可以是,1,999,2000,1999.
每两个为一个对,第一个为开始位置,第二个为重复次数。
还有bitset的空间分配,本直接,很暴力,直接2倍,如果数据量少没有问题,但是如果本身就有1亿了,再double 已经是个问题,所以可以分层优化。
所有的这些缺点在roaringbitmap里详细说明。可以参考我的文章
public class BitSet implements Cloneable, java.io.Serializable
本来想去找个图片,结果没找到,简单点。
如果有一个Set 里面存放了(整数)1,3,4,5,23,23,12,65这些数,如果直接存储需要8×32位 ;
如果采用位图,只需要用两个long整型串联。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | | | | | | | | | |
比如1,第一个long的第2个位为1
比如4,第一个long的第2个位为1
比如65,第二个long的第2个位为1
所以数据存储时x:
long []value
value[x/64] = value [x/64] |
1L<<x
value[x/64] 表示数据将放在第几个long 中, 因为1l 是以64为周期循环移动,会得到具体的存放位置。
x/64 = x>>6
查看Java 的bitSet的源码:
实际存放的位置
private long[] words;
初始长度为1
public BitSet() { initWords(BITS_PER_WORD); sizeIsSticky = false; }
添加数据。添加数据会
public void set(int bitIndex){
if(bitIndex <0)
throw new IndexOutOfBoundsException("bitIndex < 0: "+ bitIndex);
//这里执行的是 bitIndex >> 6;
int wordIndex = wordIndex(bitIndex);
//看看是否需要扩充。
expandTo(wordIndex);
words[wordIndex]|=(1L<< bitIndex);//Restores invariants
checkInvariants();
}
这里扩展成倍数扩展,没有优化
private void ensureCapacity(int wordsRequired) { if (words.length < wordsRequired) { // Allocate larger of doubled size or required size int request = Math.max(2 * words.length, wordsRequired); words = Arrays.copyOf(words, request); sizeIsSticky = false; } }
其他几个重要操作:add 直接是long的& ,比单个位操作要快,
public void and(BitSet set) { if (this == set) return; while (wordsInUse > set.wordsInUse) words[--wordsInUse] = 0; // Perform logical AND on words in common for (int i = 0; i < wordsInUse; i++) words[i] &= set.words[i]; recalculateWordsInUse(); checkInvariants(); }
其他还有xor,or 等。
不管怎么,bitset 初步解决了数据存储问题。但是还有很多优化问题,
比如:1)需要存储的数据只是一个1亿,那么也需要用1亿/64个long表示。
再比如 连续的 1,2,3,4,5,6 。。。1000.. 也需要存储1000/64个整数。
对于第一种 直接用ArrayList 比 bitset 节约空间。
第二种,采用run of length 比较好。比如开始位 1,重复999 . 所以只需要存储,1,999 就可以了,如果还有,
2000-4000 , 可以是,1,999,2000,1999.
每两个为一个对,第一个为开始位置,第二个为重复次数。
还有bitset的空间分配,本直接,很暴力,直接2倍,如果数据量少没有问题,但是如果本身就有1亿了,再double 已经是个问题,所以可以分层优化。
所有的这些缺点在roaringbitmap里详细说明。可以参考我的文章
roaringbitmap 源代码分析
。相关文章推荐
- jdk 源码分析(5)java ConcurrentSkipListMap结构
- jdk 源码分析(4) java Set 结构
- jdk 源码分析(1)java hashmap的结构
- jdk 源码分析(2)java hashtable的结构及hashMap对比
- BitSet数据结构以及jdk中实现源码分析
- Java Collections Framework之ArrayList源码分析(基于JDK1.6)
- Java Collections Framework之Collections源码分析(基于JDK1.6)
- Java Collections Framework之HashSet及LinkedHashSet源码分析(基于JDK1.6)
- Java Collections Framework之Queue(LinkedList实现)源码分析(基于JDK1.6)
- BitSet数据结构以及jdk中实现源码分析
- java学习之旅56--数组_StringBuilder和StringBuffer的使用_常用方法_方法链的实现_JDK源码分析
- Java Collections Framework之LinkedHashMap源码分析(基于JDK1.6)(??)
- java学习之旅59--模拟ArrayList容器的底层实现_JDK源码分析ArrayList
- (7) java源码分析------之ArrayList (对应数据结构中线性表中的顺序表,JDK1.6)
- java学习之旅57、58--数组_StringBuilder和StringBuffer的使用_JDK源码分析内部机制、常用方法补充_常见面试题答法
- JDK源码分析:java.lang.Boolean
- JDK源码分析之 java.lang.Boolean
- Java Collections Framework之LinkedList源码分析(基于JDK1.6)
- Java concurrent Framework并发容器之ConcurrentHashMap(Doug Lea 非JDK版)源码分析
- JDK源码分析之java.util.ArrayList