今天主要讲述roaringbitmap的add计算。
自己带上来源,防拷贝:http://blog.csdn.net/chenfenggang/article/details/74788617
先判断高位是否存在相同的,如果相同,再低位的容器相add。否则,直接跳过
public static RoaringBitmap and(final RoaringBitmap x1, final RoaringBitmap x2) {
final RoaringBitmap answer = new RoaringBitmap();
final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
int pos1 = 0, pos2 = 0;
while (pos1 < length1 && pos2 < length2) {
final short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
if (s1 == s2) { //相同则求交集,
final Container c1 = x1.highLowContainer.getContainerAtIndex(pos1);
final Container c2 = x2.highLowContainer.getContainerAtIndex(pos2);
final Container c = c1.and(c2);
if (c.getCardinality() > 0) {
answer.highLowContainer.append(s1, c);
}
++pos1;
++pos2;
} else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2 //不同直接移位pos1到 接近相同的位置
pos1 = x1.highLowContainer.advanceUntil(s2, pos1);
} else { // s1 > s2
pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
}
}
return answer;
}
advanceUntil的主要作用是找到下一个位置。
所以今天主要是正对bitmapContainer 和 arrayContainer 以及runContainer之间的add计算。
几个基本准则。
add满足交换律:也就是 runContainer.add(runContainer) = runContainer.add(runContainer);
add满足最小准则:。 bitmapContainer.add(arrayContainer) .结果一定是arrayContainer能放下。
几个加法
1)首先arrayContainer.add(arrayContainer)
@Override
public ArrayContainer and(final ArrayContainer value2) {
ArrayContainer value1 = this;
final int desiredCapacity = Math.min(value1.getCardinality(), value2.getCardinality());
ArrayContainer answer = new ArrayContainer(desiredCapacity);
answer.cardinality = Util.unsignedIntersect2by2(value1.content, value1.getCardinality(),
value2.content, value2.getCardinality(), answer.content);
return answer;
}
这里主要是求出最小能使用到空间,然后求交集。求交集unsignedIntersect2by2 这个做了一些优化。
如果两者直接的差距大于25倍(以前的代码好像是64,所以这个值不值得是统计结果还是测试结果。)采用小数组每次移动一位。
然后跳跃性移动大数组。
否则采用两者都只是移动到下一位,然后进行判断。
@Override
public ArrayContainer and(final ArrayContainer value2) {
ArrayContainer value1 = this;
final int desiredCapacity = Math.min(value1.getCardinality(), value2.getCardinality());
ArrayContainer answer = new ArrayContainer(desiredCapacity);
answer.cardinality = Util.unsignedIntersect2by2(value1.content, value1.getCardinality(),
value2.content, value2.getCardinality(), answer.content);
return answer;
}
第二 bitmap + bitmap
首先估计一下and操作后的长度,如果大于4096 则用bitmap 这个计算简单,否则用Array
@Override
public Container and(final BitmapContainer value2) {
int newCardinality = 0;
for (int k = 0; k < this.bitmap.length; ++k) {
newCardinality += Long.bitCount(this.bitmap[k] & value2.bitmap[k]);
}
if (newCardinality > ArrayContainer.DEFAULT_MAX_SIZE) {
final BitmapContainer answer = new BitmapContainer();
for (int k = 0; k < answer.bitmap.length; ++k) {
answer.bitmap[k] = this.bitmap[k] & value2.bitmap[k];
}
answer.cardinality = newCardinality;
return answer;
}
ArrayContainer ac = new ArrayContainer(newCardinality);
Util.fillArrayAND(ac.content, this.bitmap, value2.bitmap);
ac.cardinality = newCardinality;
return ac;
}
第三 bitmap+array
因为array and bitmap = bitmap and array。所以实现代码放在bitmap里面
@Override
public ArrayContainer and(final ArrayContainer value2) {
final ArrayContainer answer = new ArrayContainer(value2.content.length);
int c = value2.cardinality;
for (int k = 0; k < c; ++k) {
short v = value2.content[k];
answer.content[answer.cardinality] = v;
answer.cardinality += this.bitValue(v);
}
return answer;
}
这个代码好像缺了点什么。应该是循环内部加一个判断才对否则就只直接返回array了
for (int k = 0; k < c; ++k) {
short v = value2.content[k];
if(this.contains(v)) {
answer.content[answer.cardinality] = v;
answer.cardinality += this.bitValue(v);
}
}
吓得我感觉去git 提交的一个issue.也不知道会有什么结果。
没想到还真给我回复了,可惜我错了,里面用来一个bitValue。如果这个bitValue==1 则移位到一个坑中。否则即使你放任何值
都会被后面的值覆盖。
这个比较狠。轻松找到是否存在。
protected long bitValue(final short i) {
final int x = Util.toIntUnsigned(i);
return (bitmap[x / 64] >>> x ) & 1;
}
run+array 和run+bitmap 思路和上面的差不多,总而言之就是。先确定范围。然后在计算。然后再优化计算。
未完待续。。。