java数据结构与算法总结(二十五)--初识BitSet之API
原文链接
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相关推荐
- 【Java数据结构与算法】第十五章 B树、B+树和B*树
第十五章 B树.B+树和B*树 文章目录 第十五章 B树.B+树和B*树 一.B树 1.引入 2.介绍 二.B+树 1.引入 2.介绍 三.B*树 1.介绍 一.B树 1.引入 为什么数据库索引要使用 ...
- Java数据结构与算法(二)
Java数据结构与算法(二) 第六章 递归 1 递归应用场景 2 递归的概念 3 递归调用机制 4 递归能解决什么样的问题 5 递归需要遵守的重要规则 6 递归-迷宫问题 6.1 迷宫问题 6.2 代 ...
- java常见面试考点(二十五):CAS是什么
java常见面试考点 往期文章推荐: java常见面试考点(二十):Elasticsearch 和 solr 的区别 java常见面试考点(二十一):单点登录 java常见面试考点(二十二 ...
- Java数据结构和算法(二):数组
上篇博客我们简单介绍了数据结构和算法的概念,对此模糊很正常,后面会慢慢通过具体的实例来介绍.本篇博客我们介绍数据结构的鼻祖--数组,可以说数组几乎能表示一切的数据结构,在每一门编程语言中,数组都是重要 ...
- 数据结构与算法笔记(十五)—— 散列(哈希表)
一.前沿 1.1.直接寻址表 当关键字的全域U比较小时,直接寻址是一种简单而有效的技术.假设某应用要用到一个动态集合,其中每个元素都有一个取自全域U={0,1,-,m-1)的关键字,此处m是一个不很大 ...
- Java数据结构和算法(二)——数组
上篇博客我们简单介绍了数据结构和算法的概念,对此模糊很正常,后面会慢慢通过具体的实例来介绍.本篇博客我们介绍数据结构的鼻祖--数组,可以说数组几乎能表示一切的数据结构,在每一门编程语言中,数组都是重要 ...
- JAVA常见算法题(二十五)
/*** Java实现中文数字转换为阿拉伯数字* * * @author WQ**/ public class Demo26 {public static void main(String[] arg ...
- 【Java数据结构与算法】第十二章 哈夫曼树和哈夫曼编码
第十二章 哈夫曼树和哈夫曼编码 文章目录 第十二章 哈夫曼树和哈夫曼编码 一.哈夫曼树 1.基本术语 2.构建思路 3.代码实现 三.哈夫曼编码 1.引入 2.介绍 3.代码实现哈夫曼编码综合案例 一 ...
- 【Java数据结构与算法】第十九章 贪心算法、Prim算法和Kruskal算法
第十九章 贪心算法.Prim算法和Kruskal算法 文章目录 第十九章 贪心算法.Prim算法和Kruskal算法 一.贪心算法 1.介绍 2.支付问题 二.Prim算法 1.最小生成树 2.介绍 ...
- 【Java数据结构与算法】第十六章 图
第十六章 图 文章目录 第十六章 图 一.图 1.介绍 2.基本术语 3.邻接矩阵 4.邻接表和逆邻接表 5.十字链表 二.深度优先遍历 三.广度优先遍历 四.代码实现 一.图 1.介绍 图相较于前面 ...
最新文章
- AI一分钟 | 美女机器人竟然想生孩子,太可怕了!比尔·盖茨当选中国工程院外籍院士
- Android模拟器入门
- Spring Boot 实战 —— MyBatis(注解版)使用方法
- Linux系统基本命令之vim编辑器的使用
- java中注解动态传参_SpringMVC之注解、传参、返回值及拦截器
- Touch事件UIControlEvents详解
- 还原virtual函数的本质-----C++
- SAP-MM:发票、贷方凭证、事后借记、后续贷记
- python 中【example[I] for example in dataset】的理解
- uml c语言函数流程图,UML流程图模板分享
- Ethereum Casper 101
- 如何免费下载优质的PPT模板?
- mysql报错You do not have the SUPER privilege and binary logging is enabled
- Kettle spoon 工具实战分享
- 计算机显卡型号中数字含义详解,显卡型号全解读:那么多字母如何理解?又分别代表啥意思?...
- 科学防疫宣传实践总结报告
- Windows 本地账户
- Openjudge NOI题库 ch0111/10 河中跳房子|NOIP2015 day2 stone
- 1.NanoPi M1(全志H3)基于wiringPi的GPIO控制总结
- win10禁用笔记本原本键盘
热门文章
- c++ 圆整(取整)相关函数大全(rint lrint llrint round ceil floor trunc)
- fmx android stylebook 白边
- 随机抽样方法——DataFrame.sample()
- ​【原型设计】8种原型设计工具介绍​
- PS的工具介绍和使用方法
- 怎么用python编写个apk_python自动安装apk文件
- Java怎样在饼状图上标注数字_饼状图 - java_jun - 博客园
- 从 0 到 1,开发一个智能问答机器人
- 巧妙设置excel透明字体
- h5 video标签