您的位置:首页 > 编程语言 > Java开发

jdk 源码分析(6)java BitSet结构

2017-08-02 21:39 736 查看
虽然bitSet取名有set,但确实不是Set的子集

public class BitSet implements Cloneable, java.io.Serializable


本来想去找个图片,结果没找到,简单点。

如果有一个Set 里面存放了(整数)1,3,4,5,23,23,12,65这些数,如果直接存储需要8×32位 ;
如果采用位图,只需要用两个long整型串联。

 0
 1




 6



 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