理解BitSet
先来看几道面试题:
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的更多相关文章
- matlab bitset的理解
在阅读别人的matlab程序中,发现了这个bitset函数.于是查阅资料搞明白了大概意思,意思如下: B= bitset(A,pos,V) 将A以二进制来表示,并将第pos个位置, 设置为 V 的值, ...
- [转]深入理解Java 8 Lambda(类库篇——Streams API,Collectors和并行)
以下内容转自: 作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-l ...
- Java 集合深入理解(12):古老的 Vector
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天刮台风,躲屋里看看 Vector ! 都说 Vector 是线程安全的 ArrayList,今天来根据源码看看是不是这 ...
- Java数据结构: java.util.BitSet源码学习
接着上一篇Blog:一道面试题与Java位操作 和 BitSet 库的使用,分析下Java源码中BitSet类的源码. 位图(Bitmap),即位(Bit)的集合,是一种常用的数据结构,可用于记录大量 ...
- C++ Primer学习笔记2--c++标准库中的 vector、string 和 bitset 类型
一.string #include <string> using std::string 初始化函数: string s1; 默认构造函数 s1 为空串 ...
- 使用bitset实现毫秒级查询
前言 因为业务要求api的一次请求响应时间在10ms以内,所以传统的数据库查询操作直接被排除(网络io和磁盘io).通过调研,最终使用了bieset,目前已经正常运行了很久 *** bitset介绍 ...
- [三]java8 函数式编程Stream 概念深入理解 Stream 运行原理 Stream设计思路
Stream的概念定义 官方文档是永远的圣经~ 表格内容来自https://docs.oracle.com/javase/8/docs/api/ Package java.util.s ...
- 深入理解C++11【4】
[深入理解C++11[4]] 1.基于范围的 for 循环 C++98 中需要告诉编译器循环体界面范围.如for,或stl 中的for_each: int main() { ] = { , , , , ...
- P2347 砝码称重-DP方案数-bitset
P2347 砝码称重 DP做法 : 转化为 01背包. 进行方案数 更新.最后统计种类. #include<bits/stdc++.h> using namespace std; #def ...
随机推荐
- telent connection refused
1.问题场景 Centos7 做flume案例时,telnet hadoop-senior03.itguigu.com 44444 总是Connection redused, Trying 192.1 ...
- Spark运行模式_spark自带cluster manager的standalone cluster模式(集群)
这种运行模式和"Spark自带Cluster Manager的Standalone Client模式(集群)"还是有很大的区别的.使用如下命令执行应用程序(前提是已经启动了spar ...
- 企业SVN版本管理与代码上线方案
1.SVN服务实战 1) 什么是SVN(Subversion)? Svn(subversion)是近年来崛起的非常优秀的版本管理工具,与CVS管理工具一样,SVN是一个跨平台的开源的版本控制系统.Sv ...
- Go语言中的流程控制
1 概述 Go语言提供了条件分支 if,状态分支 switch,循环 for,跳转 goto,延迟执行 defer,这些流程控制语句.分别作说明如下: 2 条件分支 if 依据条件是否满足确定执行哪个 ...
- vue生命周期和react生命周期对比
一 vue的生命周期如下图所示(很清晰)初始化.编译.更新.销毁 二 vue生命周期的栗子 注意触发vue的created事件以后,this便指向vue实例,这点很重要 <!DOCTYPE ht ...
- VS2013 执行Enable-Migrations,产生错误的解决办法
我的错误是:提示文件或资源没有找到”Microsoft.VisualStudio.Shell, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b0 ...
- Caliburn.Micro 杰的入门教程1(翻译)
Caliburn.Micro 杰的入门教程1(原创翻译)Caliburn.Micro 杰的入门教程2 ,了解Data Binding 和 Events(翻译)Caliburn.Micro 杰的入门教程 ...
- 北京Uber优步司机奖励政策(2月23日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- R语言使用过程中出现的问题--attach()函数的使用
使用attach(file)时,一定要配合使用detach(file),否则再此运行程序时极易出现问题,The following objects are masked ... 此外工作空间中不能有与 ...
- 一文带你了解 Raft 一致性协议的关键点
此文已由作者孙建良授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Raft 协议的发布,对分布式行业是一大福音,虽然在核心协议上基本都是师继 Paxos 祖师爷(lampor ...