java bitsieve_java 之BitSet 介绍

6ec70276a8b52bc7d40686e553874caa.png

java的BitSet在jdk1.0中就已经存在了。因为平时用的少,没有注意,最近在看bitmap算法时,看见说是Java中的bitSet中就用了bitMap的思想,于是就查阅了相关BitSet的相关资料。.

介绍:

该类实现了一个根据需要增长的位向量。 位组的每个组件都具有boolean值。 BitSet的位由非负整数索引。可以检查,设置或清除各个索引位。 一个BitSet可用于通过逻辑AND,逻辑包含OR和逻辑异或运算来修改另一个BitSet的内容。

默认情况下,集合中的所有位最初都具有值false 。

每个位集都有一个当前大小,即当前位集使用的空间位数。 请注意,大小与位集的实现有关,因此它可能随实现而改变。 位集的长度与位集的逻辑长度有关,并且与实现无关的定义。

除非另有说明,否则将null参数传递给BitSet任何方法BitSet将生成NullPointerException 。

如果没有外部同步,多线程使用BitSet是不安全的。

构造方法摘要 :

构造器 描述

1. BitSet() 创建一个新的位集。 所有位最初都是false.

2.BitSet(int nbits)创建一个位集,其初始大小足以显式表示索引范围为0到nbits-1

方法摘要:

变量和类型 方法 描述

1.void and(BitSet set) 使用参数位设置执行此目标位设置的逻辑 AND 。

2.void andNot(BitSet set) 清除此 BitSet的所有位,其相应位在指定的 BitSet设置。

3.int cardinality() 返回此 BitSet设置为 true的 BitSet 。

4.void clear() 将此BitSet中的所有位设置为 false 。

5.void clear(int bitIndex) 将索引指定的位设置为 false 。

6.void clear(int fromIndex, int toIndex) 将指定的 fromIndex (含)到指定的 toIndex (不包括)的位设置为 false 。

7.Object clone() 克隆此 BitSet会生成一个 BitSet相等的新 BitSet 。

8.boolean equals(Object obj) 将此对象与指定的对象进行比较。

9.void flip(int bitIndex) 将指定索引处的位设置为其当前值的补码。

10.void flip(int fromIndex, int toIndex) 将指定的每一位 fromIndex (含)到指定 toIndex (独家)为其当前值的补码。

11.boolean get(int bitIndex) 返回具有指定索引的位的值。

12.BitSet get(int fromIndex, int toIndex) 返回一个新的 BitSet由 BitSet从 fromIndex (含)到 toIndex (独家)的位组成。

13.int hashCode() 返回此位集的哈希码值。

14.boolean intersects(BitSet set) 如果指定的 BitSet任何位设置为 true true在此 BitSet中也设置为 true ,则返回true。

15.boolean isEmpty() 如果此 BitSet包含设置为 true位,则返回true。

16.int length() 返回此 BitSet的“逻辑大小”: BitSet中最高设置位的 BitSet加1。

17.int nextClearBit(int fromIndex) 返回在指定的起始索引之上或之后发生的设置为 false的第一个位的索引。

18.int nextSetBit(int fromIndex) 返回在指定的起始索引之上或之后发生的设置为 true的第一个位的索引。

19.void or(BitSet set) 使用位设置参数执行此位设置的逻辑 OR 。

20.int previousClearBit(int fromIndex) 返回在指定的起始索引之前或之前发生的设置为 false的最近位的索引。

21.int previousSetBit(int fromIndex) 返回在指定的起始索引之前或之前发生的设置为 true的最近位的索引。

22.void set(int bitIndex) 将指定索引处的位设置为 true 。

23.void set(int bitIndex, boolean value) 将指定索引处的位设置为指定值。

24.void set(int fromIndex, int toIndex) 将指定的 fromIndex (含)到指定的 toIndex (不包括)的位设置为 true 。

25.void set(int fromIndex, int toIndex, boolean value) 将指定的 fromIndex (含)到指定的 toIndex (不包括)的位设置为指定的值。

26.int size() 返回此 BitSet实际使用的空间位数,以表示位值。

27.IntStream stream() 返回此 BitSet包含处于set状态的位的索引流。

28.byte[] toByteArray() 返回包含此位集中所有位的新字节数组。

29.long[] toLongArray() 返回包含此位集中所有位的新长数组。

30.String toString() 返回此位集的字符串表示形式。

31.static BitSet valueOf(byte[] bytes) 返回包含给定字节数组中所有位的新位集。

32.static BitSet valueOf(long[] longs) 返回包含给定long数组中所有位的新位集。

33.static BitSet valueOf(ByteBuffer bb) 返回一个新的位集,其中包含位置和限制之间给定字节缓冲区中的所有位。

34.static BitSet valueOf(LongBuffer lb) 返回一个新的位集,其中包含位置和限制之间给定长缓冲区中的所有位。

35.void xor(BitSet set) 使用位设置参数执行此位设置的逻辑 异或 。

以下内容参照:https://blog.csdn.net/jiangnan2014/article/details/53735429

基本原理

BitSet是位操作的对象,值只有0或1即false和true,内部维护了一个long数组,初始只有一个long,所以BitSet最小的size是64,当随着存储的元素越来越多,BitSet内部会动态扩充,最终内部是由N个long来存储,这些针对操作都是透明的。

用1位来表示一个数据是否出现过,0为没有出现过,1表示出现过。使用用的时候既可根据某一个是否为0表示,此数是否出现过。

一个1G的空间,有 8*1024*1024*1024=8.58*10^9bit,也就是可以表示85亿个不同的数

使用场景

常见的应用是那些需要对海量数据进行一些统计工作的时候,比如日志分析、用户数统计等等

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

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

代码示例:

package util;

import java.util.Arrays;

import java.util.BitSet;

public class BitSetDemo {

/**

* 求一个字符串包含的char

*

*/

public static void containChars(String str) {

BitSet used = new BitSet();

for (int i = 0; i < str.length(); i++)

used.set(str.charAt(i)); // set bit for char

StringBuilder sb = new StringBuilder();

sb.append("[");

int size = used.size();

System.out.println(size);

for (int i = 0; i < size; i++) {

if (used.get(i)) {

sb.append((char) i);

}

}

sb.append("]");

System.out.println(sb.toString());

}

/**

* 求素数 有无限个。一个大于1的自然数,如果除了1和它本身外,不能被其他自然数整除(除0以外)的数称之为素数(质数) 否则称为合数

*/

public static void computePrime() {

BitSet sieve = new BitSet(1024);

int size = sieve.size();

for (int i = 2; i < size; i++)

sieve.set(i);

int finalBit = (int) Math.sqrt(sieve.size());

for (int i = 2; i < finalBit; i++)

if (sieve.get(i))

for (int j = 2 * i; j < size; j += i)

sieve.clear(j);

int counter = 0;

for (int i = 1; i < size; i++) {

if (sieve.get(i)) {

System.out.printf("%5d", i);

if (++counter % 15 == 0)

System.out.println();

}

}

System.out.println();

}

/**

* 进行数字排序

*/

public static void sortArray() {

int[] array = new int[] { 423, 700, 9999, 2323, 356, 6400, 1,2,3,2,2,2,2 };

BitSet bitSet = new BitSet(2 << 13);

// 虽然可以自动扩容,但尽量在构造时指定估算大小,默认为64

System.out.println("BitSet size: " + bitSet.size());

for (int i = 0; i < array.length; i++) {

bitSet.set(array[i]);

}

//剔除重复数字后的元素个数

int bitLen=bitSet.cardinality();

//进行排序,即把bit为true的元素复制到另一个数组

int[] orderedArray = new int[bitLen];

int k = 0;

for (int i = bitSet.nextSetBit(0); i >= 0; i = bitSet.nextSetBit(i + 1)) {

orderedArray[k++] = i;

}

System.out.println("After ordering: ");

for (int i = 0; i < bitLen; i++) {

System.out.print(orderedArray[i] + "\t");

}

System.out.println("iterate over the true bits in a BitSet");

//或直接迭代BitSet中bit为true的元素iterate over the true bits in a BitSet

for (int i = bitSet.nextSetBit(0); i >= 0; i = bitSet.nextSetBit(i + 1)) {

System.out.print(i+"\t");

}

System.out.println("---------------------------");

}

/**

* 将BitSet对象转化为ByteArray

* @param bitSet

* @return

*/

public static byte[] bitSet2ByteArray(BitSet bitSet) {

byte[] bytes = new byte[bitSet.size() / 8];

for (int i = 0; i < bitSet.size(); i++) {

int index = i / 8;

int offset = 7 - i % 8;

bytes[index] |= (bitSet.get(i) ? 1 : 0) << offset;

}

return bytes;

}

/**

* 将ByteArray对象转化为BitSet

* @param bytes

* @return

*/

public static BitSet byteArray2BitSet(byte[] bytes) {

BitSet bitSet = new BitSet(bytes.length * 8);

int index = 0;

for (int i = 0; i < bytes.length; i++) {

for (int j = 7; j >= 0; j--) {

bitSet.set(index++, (bytes[i] & (1 << j)) >> j == 1 ? true

: false);

}

}

return bitSet;

}

/**

* 简单使用示例

*/

public static void simpleExample() {

String names[] = { "Java", "Source", "and", "Support" };

BitSet bits = new BitSet();

for (int i = 0, n = names.length; i < n; i++) {

if ((names[i].length() % 2) == 0) {

bits.set(i);

}

}

System.out.println(bits);

System.out.println("Size : " + bits.size());

System.out.println("Length: " + bits.length());

for (int i = 0, n = names.length; i < n; i++) {

if (!bits.get(i)) {

System.out.println(names[i] + " is odd");

}

}

BitSet bites = new BitSet();

bites.set(0);

bites.set(1);

bites.set(2);

bites.set(3);

bites.andNot(bits);

System.out.println(bites);

}

public static void main(String args[]) {

//BitSet使用示例

BitSetDemo.containChars("How do you do? 你好呀");

BitSetDemo.computePrime();

BitSetDemo.sortArray();

BitSetDemo.simpleExample();

//BitSet与Byte数组互转示例

BitSet bitSet = new BitSet();

bitSet.set(3, true);

bitSet.set(98, true);

System.out.println(bitSet.size()+","+bitSet.cardinality());

//将BitSet对象转成byte数组

byte[] bytes = BitSetDemo.bitSet2ByteArray(bitSet);

System.out.println(Arrays.toString(bytes));

//在将byte数组转回来

bitSet = BitSetDemo.byteArray2BitSet(bytes);

System.out.println(bitSet.size()+","+bitSet.cardinality());

System.out.println(bitSet.get(3));

System.out.println(bitSet.get(98));

for (int i = bitSet.nextSetBit(0); i >= 0; i = bitSet.nextSetBit(i + 1)) {

System.out.print(i+"\t");

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值