原文链接

1.BitSet类的基本原理

类实现了一个按需增长的位向量。用一位来表示一个数据是否出现过,0表示没有出现过,1表示没有出现过

默认情况下,set中所有位的初识值都是0(或者false)。

多个线程操作一个BitSet是不安全的。

2.API解析

2.1 底层数据结构

  • 内部维护了一个long数组,所以数组words中的每个元素word默认是64位的long值。

  •  ADDRESS_BITS_PER_WORD = 6:每个word值需要6个bit来表示地址:64 = 2^6
  • BITS_PER_WORD = 64:每个word有64位,即一个long数据
  • BIT_INDEX_MASK:每个word有64位,最大索引值是64 - 1 = 63

  • wordsInUse:BitSet的逻辑大小,即底层long数组的size
  • sizeIsSticky:BitSet的大小是否是用户指定的,默认是false

2.2 构造函数

  • 默认的构造参数
  • 带参数的构造参数
public BitSet() {initWords(BITS_PER_WORD);sizeIsSticky = false;//用户未指定大小
}
    public BitSet(int nbits) {// nbits can't be negative; size 0 is OKif (nbits < 0)throw new NegativeArraySizeException("nbits < 0: " + nbits);initWords(nbits);sizeIsSticky = true;//用户指定大小}

其中主要包括的方法是:

    private void initWords(int nbits) {words = new long[wordIndex(nbits-1) + 1];}

根据默认的数据的个数或是用户指定的个数来初始化long数组:

当nbits <= 64时,words = new long[1];

当nbits > 64 and nbits <= 128时,words = new long[2];

以此类推,即用户需要存储的数据个数

  • 私有的构造参数

        private BitSet(long[] words) {this.words = words;this.wordsInUse = words.length;checkInvariants();}
  • 不允许外部类 构建本类的实例 常见于单例模式
  • 2.3 常用方法

  • set方法
  •     public void set(int bitIndex) {if (bitIndex < 0)throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);int wordIndex = wordIndex(bitIndex);expandTo(wordIndex);words[wordIndex] |= (1L << bitIndex); // Restores invariantscheckInvariants();}
        public void set(int bitIndex, boolean value) {if (value)set(bitIndex);elseclear(bitIndex);}

    其中 wordIndex = wordIndex(bitIndex) 是通过简单的右移运算来判断这个值代表的索引在long数组中的下标索引。

    比如:bitIndex = 16

  • 16 >> 6 = 0,代表16这个值存储在数组words[0]中,
  • 然后通过位运算中的或运算 :words[0] = words[0] | (1L << 16) 将words[0]中从右往左数第16个bit位置为1(即true).
  • clear方法
    public void clear(int bitIndex) {if (bitIndex < 0)throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);int wordIndex = wordIndex(bitIndex);if (wordIndex >= wordsInUse)return;words[wordIndex] &= ~(1L << bitIndex);recalculateWordsInUse();checkInvariants();}

跟set方法一样,通过位运算中的与运算:words[wordIndex] &= ~(1L << bitIndex)

将从右往左数,第bitIndex位的bit置为0(即false)。不管原来该位上是否是0,都置为0

  • and方法
    public void and(BitSet set) {if (this == set)return;while (wordsInUse > set.wordsInUse)words[--wordsInUse] = 0;// Perform logical AND on words in commonfor (int i = 0; i < wordsInUse; i++)words[i] &= set.words[i];recalculateWordsInUse();checkInvariants();}

得到的结果是两个BitSet中共有的数据,相当于交集

  • or方法
    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 commonfor (int i = 0; i < wordsInCommon; i++)words[i] |= set.words[i];// Copy any remaining wordsif (wordsInCommon < set.wordsInUse)System.arraycopy(set.words, wordsInCommon,words, wordsInCommon,wordsInUse - wordsInCommon);// recalculateWordsInUse() is unnecessarycheckInvariants();}

得到的是两个BitSet中的并集

  • xor方法
    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 commonfor (int i = 0; i < wordsInCommon; i++)words[i] ^= set.words[i];// Copy any remaining wordsif (wordsInCommon < set.wordsInUse)System.arraycopy(set.words, wordsInCommon,words, wordsInCommon,set.wordsInUse - wordsInCommon);recalculateWordsInUse();checkInvariants();}
  • 得到的是当前BitSet中独有的数据,相当于差集

  • size方法

    public int size() {return words.length * BITS_PER_WORD;}
  • 返回的是BitSet的逻辑大小,即底层数组的大小 * 每个word值占用的bit位(默认是64bit)

3.总结

BitSet适用于存储无重复的整数。对于一堆无序的不重复的随机大数据,应用场景主要有:

  • 统计没有出现的数
  • 对这些数据进行排序
  • 压缩存储(一个GB的内存可以存储 1024 * 1024 * 1024 * 8 bit的数)

BitSet选择long数组作为底层数据结构是因为BitSet提供 and和or等的位运算,需要对BitSet中的所有bit位做and或者or,遍历数组的时候性能比较高,使用long可以使循环的次数达到最小。

测试类

import java.util.BitSet;public class BitSetDemo {public static void main(String args[]) {BitSet bits1 = new BitSet(16);//wordsInUse = 0,sizeIsSticky = trueBitSet bits2 = new BitSet(16);BitSet bits3 = new BitSet();BitSet bits4 = new BitSet();//wordsInUse = 0,sizeIsSticky = false// set some bitsfor(int i=0; i<16; i++) {if((i%2) == 0) bits1.set(i);if((i%5) != 0) bits2.set(i);}for(int i = 0;i < 64;i++)bits3.set(i);for(int i = 0;i < 65;i++)bits4.set(i);System.out.println("Initial pattern in bits1: ");System.out.println(bits1);System.out.println(bits1.size());System.out.println("\nInitial pattern in bits2: ");System.out.println(bits2);System.out.println(bits2.size());System.out.println("Initial pattern in bits3: ");System.out.println(bits3);System.out.println(bits3.size());System.out.println("\nInitial pattern in bits4: ");System.out.println(bits4);System.out.println(bits4.size());// AND bits//相当于找过两个set的交集bits2.and(bits1);System.out.println("\nbits2 AND bits1: ");System.out.println(bits2);// OR bits//相当于并集bits2.or(bits1);System.out.println("\nbits2 OR bits1: ");System.out.println(bits2);// XOR bits//相当于差集bits2.xor(bits1);System.out.println("\nbits2 XOR bits1: ");System.out.println(bits2);}
}

java数据结构与算法总结(二十五)--初识BitSet之API相关推荐

  1. 【Java数据结构与算法】第十五章 B树、B+树和B*树

    第十五章 B树.B+树和B*树 文章目录 第十五章 B树.B+树和B*树 一.B树 1.引入 2.介绍 二.B+树 1.引入 2.介绍 三.B*树 1.介绍 一.B树 1.引入 为什么数据库索引要使用 ...

  2. Java数据结构与算法(二)

    Java数据结构与算法(二) 第六章 递归 1 递归应用场景 2 递归的概念 3 递归调用机制 4 递归能解决什么样的问题 5 递归需要遵守的重要规则 6 递归-迷宫问题 6.1 迷宫问题 6.2 代 ...

  3. java常见面试考点(二十五):CAS是什么

    java常见面试考点 往期文章推荐:   java常见面试考点(二十):Elasticsearch 和 solr 的区别   java常见面试考点(二十一):单点登录   java常见面试考点(二十二 ...

  4. Java数据结构和算法(二):数组

    上篇博客我们简单介绍了数据结构和算法的概念,对此模糊很正常,后面会慢慢通过具体的实例来介绍.本篇博客我们介绍数据结构的鼻祖--数组,可以说数组几乎能表示一切的数据结构,在每一门编程语言中,数组都是重要 ...

  5. 数据结构与算法笔记(十五)—— 散列(哈希表)

    一.前沿 1.1.直接寻址表 当关键字的全域U比较小时,直接寻址是一种简单而有效的技术.假设某应用要用到一个动态集合,其中每个元素都有一个取自全域U={0,1,-,m-1)的关键字,此处m是一个不很大 ...

  6. Java数据结构和算法(二)——数组

    上篇博客我们简单介绍了数据结构和算法的概念,对此模糊很正常,后面会慢慢通过具体的实例来介绍.本篇博客我们介绍数据结构的鼻祖--数组,可以说数组几乎能表示一切的数据结构,在每一门编程语言中,数组都是重要 ...

  7. JAVA常见算法题(二十五)

    /*** Java实现中文数字转换为阿拉伯数字* * * @author WQ**/ public class Demo26 {public static void main(String[] arg ...

  8. 【Java数据结构与算法】第十二章 哈夫曼树和哈夫曼编码

    第十二章 哈夫曼树和哈夫曼编码 文章目录 第十二章 哈夫曼树和哈夫曼编码 一.哈夫曼树 1.基本术语 2.构建思路 3.代码实现 三.哈夫曼编码 1.引入 2.介绍 3.代码实现哈夫曼编码综合案例 一 ...

  9. 【Java数据结构与算法】第十九章 贪心算法、Prim算法和Kruskal算法

    第十九章 贪心算法.Prim算法和Kruskal算法 文章目录 第十九章 贪心算法.Prim算法和Kruskal算法 一.贪心算法 1.介绍 2.支付问题 二.Prim算法 1.最小生成树 2.介绍 ...

  10. 【Java数据结构与算法】第十六章 图

    第十六章 图 文章目录 第十六章 图 一.图 1.介绍 2.基本术语 3.邻接矩阵 4.邻接表和逆邻接表 5.十字链表 二.深度优先遍历 三.广度优先遍历 四.代码实现 一.图 1.介绍 图相较于前面 ...

最新文章

  1. AI一分钟 | 美女机器人竟然想生孩子,太可怕了!比尔·盖茨当选中国工程院外籍院士
  2. Android模拟器入门
  3. Spring Boot 实战 —— MyBatis(注解版)使用方法
  4. Linux系统基本命令之vim编辑器的使用
  5. java中注解动态传参_SpringMVC之注解、传参、返回值及拦截器
  6. Touch事件UIControlEvents详解
  7. 还原virtual函数的本质-----C++
  8. SAP-MM:发票、贷方凭证、事后借记、后续贷记
  9. python 中【example[I] for example in dataset】的理解
  10. uml c语言函数流程图,UML流程图模板分享
  11. Ethereum Casper 101
  12. 如何免费下载优质的PPT模板?
  13. mysql报错You do not have the SUPER privilege and binary logging is enabled
  14. Kettle spoon 工具实战分享
  15. 计算机显卡型号中数字含义详解,显卡型号全解读:那么多字母如何理解?又分别代表啥意思?...
  16. 科学防疫宣传实践总结报告
  17. Windows 本地账户
  18. Openjudge NOI题库 ch0111/10 河中跳房子|NOIP2015 day2 stone
  19. 1.NanoPi M1(全志H3)基于wiringPi的GPIO控制总结
  20. win10禁用笔记本原本键盘

热门文章

  1. c++ 圆整(取整)相关函数大全(rint lrint llrint round ceil floor trunc)
  2. fmx android stylebook 白边
  3. 随机抽样方法——DataFrame.sample()
  4. ​【原型设计】8种原型设计工具介绍​
  5. PS的工具介绍和使用方法
  6. 怎么用python编写个apk_python自动安装apk文件
  7. Java怎样在饼状图上标注数字_饼状图 - java_jun - 博客园
  8. 从 0 到 1,开发一个智能问答机器人
  9. 巧妙设置excel透明字体
  10. h5 video标签