位图bitmap

        位图算法:bitmap是内存中连续的二进制位(bit)所组成的数据结构,位图算法主要用于对大量整数做去重和查询操作(交集、并集、差集)。因为使用的是位运算,因此性能也是很高的。

        场景一:给用户打上标签,然后对各标签进行用户数据的统计。如果标签数不多的话,以用户为中心建立标签信息就足够了。如果便签种类很大,此时应当以标签为中心,用标签来关联用户,为每个标签建立相应的位图,通过位图来统计用户信息。

        场景二:给40亿个不重复的无符号整数,没拍过序。给定一个无符号整数,如何可以高效的判断是否存在这些数据中。先通过set方法将整数放入位图中,再通过get方法判断整数是否存在。

        jdk中的BitSet就是位图算法的具体实现。

        对于左移操作:如果对于基本类型数据a进行移位操作,设a占用的bit位为count,移位shift位。则 a >> shift 等价于 a >> (shift % count)。

        运算时数据溢出:计算机运算时采用补码方式,当数据溢出时,数据从右侧开始保留指定类型位数,再转为原码得到相应的值。

如:byte a = (byte)(127 + 2) 结果为

127的补码:1111 1111

2的补码:0000 0010

补码结果为:1 0000 0001 溢出后截取为 1000 0001(保留符号位)

转原码:1111 1111 (-127)

public class BitSet implements Cloneable, java.io.Serializable {

    //一个long元素有64bit,需要移动6位
    private final static int ADDRESS_BITS_PER_WORD = 6;
    //位图中的bit信息存入long型数组中,我们不关心long值为多少,而关心每一bit位是1或是0.
    //若只有两个元素,则组成的位图结构为words[1] words[0]对应的二进制
    private long[] words;
    //记录当前用到的数组索引
    private transient int wordsInUse = 0;

    private static int wordIndex(int bitIndex) {
        return bitIndex >> ADDRESS_BITS_PER_WORD;
    }

    //往指定的bit位设置值,设置为1
    //1L << 65 等价于 1L << 1 即 1L << (65 % 64),编译时自动处理
    // 1 << 33 等价于 1 << 1 即 1 << (33 % 32)
    public void set(int bitIndex) {
        if (bitIndex < 0)
            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);

        //根据指定的bit位,找到它对应的数组位置
        int wordIndex = wordIndex(bitIndex);
        expandTo(wordIndex);

        //将bitIndex处的值置为1
        words[wordIndex] |= (1L << bitIndex); // Restores invariants

        checkInvariants();
    }

    //查询指定的bit位的值,如果为1则返回true,否则返回false
    public boolean get(int bitIndex) {
        if (bitIndex < 0)
            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);

        checkInvariants();

        int wordIndex = wordIndex(bitIndex);
        //如果指定的bit位的值为1返回true,否则返回false
        return (wordIndex < wordsInUse)
            && ((words[wordIndex] & (1L << bitIndex)) != 0);
    }

    //两个位图结构的与元素,即交集
    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();
    }

    //两个位图结构的或运算,即并集
    public void or(BitSet set) {
        if (this == set)
            return;

        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);

        if (wordsInUse < set.wordsInUse) {
            ensureCapacity(set.wordsInUse);
            wordsInUse = set.wordsInUse;
        }

        // Perform logical OR on words in common
        for (int i = 0; i < wordsInCommon; i++)
            words[i] |= set.words[i];

        // Copy any remaining words
        if (wordsInCommon < set.wordsInUse)
            System.arraycopy(set.words, wordsInCommon,
                             words, wordsInCommon,
                             wordsInUse - wordsInCommon);

        // recalculateWordsInUse() is unnecessary
        checkInvariants();
    }    

    //两个位图结构的异或运算,等同于取非,需要有全量位图
    public void xor(BitSet set) {
        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);

        if (wordsInUse < set.wordsInUse) {
            ensureCapacity(set.wordsInUse);
            wordsInUse = set.wordsInUse;
        }

        // Perform logical XOR on words in common
        for (int i = 0; i < wordsInCommon; i++)
            words[i] ^= set.words[i];

        // Copy any remaining words
        if (wordsInCommon < set.wordsInUse)
            System.arraycopy(set.words, wordsInCommon,
                             words, wordsInCommon,
                             set.wordsInUse - wordsInCommon);

        recalculateWordsInUse();
        checkInvariants();
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值