理解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 ...
随机推荐
- rails应用使用carrierwave和mini_magick上传用户头像
1. 在Gemfile添加 gem 'carrierwave' gem 'mini_magick' 执行 bundle install 2. 生成uploader rails generate upl ...
- verilog中参数传递与参数定义中#的作用(二)
一.module内部有效的定义 用parameter来定义一个标志符代表一个常量,称作符号常量,他可以提高程序的可读性和可维护性.parameter是参数型数据的关键字,在每一个赋值语句的右边都必须是 ...
- java随笔一(关于定时任务)
public class ThreadTest { class MyTask implements Runnable{ public void run() { say(); } } public vo ...
- 20145202马超《网络对抗》Exp9*_* Web安全基础实践
本实践的目标理解常用网络攻击技术的基本原理.Webgoat实践下相关实验. 1.实验后回答问题 (1)SQL注入攻击原理,如何防御 感觉上次做的也是sql注入,就是故意的非法输入(输入的是一些指令)让 ...
- jquery.validate验证,jquery.Form插件提交,主要可以异步提交文件
<script type="text/javascript"> $(function () { $form = $("#manuForm"); $b ...
- 成都优步uber司机第三组奖励政策
今天成都优步又推出了优步司机第三组,第一二组的奖励大家都晓得,但是第三组的奖励怎么样呢?还是先看看官方给出的消息. 滴滴快车单单2.5倍,注册地址:http://www.udache.com/如何注册 ...
- 在线大数据cdh迁移,从公有云迁移到私有云
1.添加新节点 2.迁移hdfs和hbase数据: 3.迁移源节点各个服务到新节点: 4.利用HA,包括hdfs,hbase master,resourcemanager的ha实现在线迁移: 5.数据 ...
- Entity Framework Core 导航属性 加载数据
Loading Related Data https://docs.microsoft.com/en-us/ef/core/querying/related-data Eager loading me ...
- Redis系列五 Redis持久化
Redis持久化 一.RDB(Redis DataBase) 1.介绍 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里. Red ...
- 前端图片转base64,转格式,转blob,上传的总结
1. 图片文件转base64 <input accept="image/gif,image/jpeg,image/jpg,image/png" type="file ...