先来看几道面试题:

1、统计40亿个数据中没有出现的数据,将40亿个不同数据进行排序。

2、现在有1千万个随机数,随机数的范围在1到1亿之间,要求写出一种算法,将1到1亿之间没有在随机数中的数求出来。

3、有一个40G大小的文件,里面存的是32位正整数记录,我需要查找其中一个文件,问如何查找?

……

有木有被上面的大大大数据吓到了无从下手啊?今天介绍的BitSet就可以解决这一问题。

简介

一个按需增长的位向量,C++和java都有提供实现。

BitSet是位操作的对象,值只有1和0。用1位来表示一个数据是否出现过,0为没有出现过,1表示出现过。使用用的时候既可根据某一个是否为0表示此数是否出现过。

比较

一般,int占4个字节,long占8个字节。而一个字节是由8个位组成的。

粗略估计,int和BitSet的比例为4*8:1,即32:1。如果是long,差距就更大了。

基本操作

1、重要属性

BitSet在java.util包下,初始大小为64位。

 /*
* BitSets are packed into arrays of "words." Currently a word is
* a long, which consists of 64 bits, requiring 6 address bits.
* The choice of word size is determined purely by performance concerns.
*/
private final static int ADDRESS_BITS_PER_WORD = 6; private long[] words;

2、构造函数

//构造函数一
public BitSet(int nbits) {
// nbits can't be negative; size 0 is OK
if (nbits < 0)
throw new NegativeArraySizeException("nbits < 0: " + nbits);
//new 一个long数组
initWords(nbits);
sizeIsSticky = true;
} private void initWords(int nbits) {
words = new long[wordIndex(nbits-1) + 1];
}
//构造函数二
private BitSet(long[] words) {
this.words = words;
this.wordsInUse = words.length;
checkInvariants();
}

3、检查函数

BitSet类中提供了两个内部检查的函数。

 /**
* Sets the field wordsInUse to the logical size in words of the bit set.
* WARNING:This method assumes that the number of words actually in use is
* less than or equal to the current value of wordsInUse!
*/
private void recalculateWordsInUse() {
// Traverse the bitset until a used word is found
int i;
for (i = wordsInUse-1; i >= 0; i--)
if (words[i] != 0)
break; wordsInUse = i+1; // The new logical size
} /**
* Every public method must preserve these invariants.
*/
private void checkInvariants() {
//wordsInUse 实际使用的long的个数
assert(wordsInUse == 0 || words[wordsInUse - 1] != 0);
assert(wordsInUse >= 0 && wordsInUse <= words.length);
assert(wordsInUse == words.length || words[wordsInUse] == 0);
}

4、扩容

跟其他可以自动扩容类相同,扩容发生在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 invariants
//检查
checkInvariants();
} private void expandTo(int wordIndex) {
int wordsRequired = wordIndex+1;
if (wordsInUse < wordsRequired) {
ensureCapacity(wordsRequired);
wordsInUse = wordsRequired;
}
} //核心扩容方法
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;
}
}

应用实例

为了方便演示,就把数字改小了。需求就是生成10个10以内的随机数,并求出20以内哪些数字没在生成的随机数中。

// 先把随机数放入list中
Random random = new Random();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int randomResult = random.nextInt(10);
list.add(randomResult);
}
//查看生产的随机数
System.out.println("产生的随机数有");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("the end"); //将随机数放入bitset中
BitSet bit = new BitSet(); for (int i = 0; i < 10; i++) {
bit.set(list.get(i));
}
//打印没有随机生产的数
for (int i = 0; i < 20; i++) {
if (!bit.get(i)) {
System.out.println(i);
}
}

理解BitSet的更多相关文章

  1. matlab bitset的理解

    在阅读别人的matlab程序中,发现了这个bitset函数.于是查阅资料搞明白了大概意思,意思如下: B= bitset(A,pos,V) 将A以二进制来表示,并将第pos个位置, 设置为 V 的值, ...

  2. [转]深入理解Java 8 Lambda(类库篇——Streams API,Collectors和并行)

    以下内容转自: 作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-l ...

  3. Java 集合深入理解(12):古老的 Vector

    点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天刮台风,躲屋里看看 Vector ! 都说 Vector 是线程安全的 ArrayList,今天来根据源码看看是不是这 ...

  4. Java数据结构: java.util.BitSet源码学习

    接着上一篇Blog:一道面试题与Java位操作 和 BitSet 库的使用,分析下Java源码中BitSet类的源码. 位图(Bitmap),即位(Bit)的集合,是一种常用的数据结构,可用于记录大量 ...

  5. C++ Primer学习笔记2--c++标准库中的 vector、string 和 bitset 类型

    一.string    #include <string>  using std::string    初始化函数:    string s1;        默认构造函数 s1 为空串 ...

  6. 使用bitset实现毫秒级查询

    前言 因为业务要求api的一次请求响应时间在10ms以内,所以传统的数据库查询操作直接被排除(网络io和磁盘io).通过调研,最终使用了bieset,目前已经正常运行了很久 *** bitset介绍 ...

  7. [三]java8 函数式编程Stream 概念深入理解 Stream 运行原理 Stream设计思路

    Stream的概念定义   官方文档是永远的圣经~     表格内容来自https://docs.oracle.com/javase/8/docs/api/   Package java.util.s ...

  8. 深入理解C++11【4】

    [深入理解C++11[4]] 1.基于范围的 for 循环 C++98 中需要告诉编译器循环体界面范围.如for,或stl 中的for_each: int main() { ] = { , , , , ...

  9. P2347 砝码称重-DP方案数-bitset

    P2347 砝码称重 DP做法 : 转化为 01背包. 进行方案数 更新.最后统计种类. #include<bits/stdc++.h> using namespace std; #def ...

随机推荐

  1. C#中访问私有成员--反射

    首先我必须承认访问一个类的私有成员不是什么好做法.大家也都知道私有成员在外部是不能被访问的.而一个类中会存在很多私有成员:如私有字段.私有属性.私有方法.对于私有成员访问,可以套用下面这种非常好的方式 ...

  2. P1803 凌乱的yyy

    P1803 凌乱的yyy 题目背景 快noip了,yyy很紧张! 题目描述 现在各大oj上有n个比赛,每个比赛的开始.结束的时间点是知道的. yyy认为,参加越多的比赛,noip就能考的越好(假的) ...

  3. #define NULL ((void *)0)引起的风波

    1. 看下宏定义的结构体 typedef struct { ]; //CMEI/IMEI ]; //server ]; //CMEI/IMEI } Options; 2. 定义的NULL #defin ...

  4. adb获取设备的序列号

    用数据线连接手机, 打开开发者模式, 并赋予相关权限, 在CMD命令行输入: adb devices 第一个参数即为设备的序列号, 第二个参数device表示设备的状态是在线.

  5. 巧用浏览器F12调试器定位系统前后端bug

    做测试的小伙伴可能用过httpwatch,firebug,fiddler,charles等抓包(数据包)工具,但实际上除了这些还有一个简单实用并的抓包工具,那就是浏览器的F12调试器. httpwat ...

  6. 第八模块:算法&设计模式、企业应用 第1章 常用算法&设计模式学习

    第八模块:算法&设计模式.企业应用 第1章 常用算法&设计模式学习

  7. TW实习日记:第29-30天

    这两天挺忙,赶工期,改bug.项目现场的同事说客户火大得不行.可是谁叫你们谈工期谈的这么紧,完全不考虑开发的情况,真的是烦人这种事情.这两天遇到的最有难度的一个点就是附件预览,搞这个改到晚上11点. ...

  8. 【springmvc+mybatis项目实战】杰信商贸-2.数据库配置

    首先我们来了解项目的架构 我们分别使用了MySql和Oracle数据库,即是异构数据库.我们做到一个平台支持多个数据库.数据库建模我们使用Sybase公司的PowerDesigner(以后简称PD), ...

  9. 并发HashMap的put操作引起死循环

    今天研读Java并发容器和框架时,看到为什么要使用ConcurrentHashMap时,其中有一个原因是:线程不安全的HashMap, HashMap在并发执行put操作时会引起死循环,是因为多线程会 ...

  10. ThinkPHP - 3 - IDE选择以及Eclipse PDT打开ThinkPHP项目

    ThinkPHP框架已部署到SAE(新浪云),且代码已获取到本地.眼前面临的问题就是,对ThinkPHP项目选择哪种开发工具(IDE)? 经过简单的查找比较,以及电脑里已装有Eclipse的因素,遂决 ...