/**
* 演示java.util.BitSet类的使用
* BitSet类表示自动增长位集合
* @author Sking
*/
package bitset;
import java.util.BitSet;
public class BitSetAPITest {
public static void main(String[] args){
//BitSet的构造函数
BitSet b1=new BitSet();
BitSet b2=new BitSet(20);
//set方法演示
for(int i=3;i<20;i+=3)
b1.set(i);
System.out.println(b1.toString());//{3, 6, 9, 12, 15, 18}
for(int i=2;i<15;i+=2)
b1.set(i, false);
System.out.println(b1.toString());//{3, 9, 15, 18}
b2.set(5, 10);
System.out.println(b2.toString());//{5, 6, 7, 8, 9}
b2.set(8,14,false);
System.out.println(b2.toString());//{5, 6, 7}
//flip方法演示
b2.flip(10,15);
System.out.println(b2.toString());//{5, 6, 7, 10, 11, 12, 13, 14}
b1.flip(15);
System.out.println(b1.toString());//{3, 9, 18}
//clear方法演示
b2.clear(10);
System.out.println(b2.toString());//{5, 6, 7, 11, 12, 13, 14}
b2.clear(6, 9);
System.out.println(b2.toString());//{5, 11, 12, 13, 14}
b2.clear();
System.out.println(b2.toString());//{}
//get方法演示
boolean get9=b1.get(9);
System.out.println(get9);//true
BitSet b3=b1.get(3,10);
System.out.println(b3.toString());//{0, 6}
b1.set(7,13);
b2.set(9,16);
System.out.println(b1.toString());//{3, 7, 8, 9, 10, 11, 12, 18}
System.out.println(b2.toString());//{9, 10, 11, 12, 13, 14, 15}
//位集操作
b1.and(b2);
System.out.println(b1.toString());//{9, 10, 11, 12}
b2.xor(b1);
System.out.println(b2.toString());//{13, 14, 15}
b1.or(b2);
System.out.println(b1.toString());//{9, 10, 11, 12, 13, 14, 15}
b3.set(13,15);
b2.andNot(b3);
System.out.println(b2.toString());//{15}
//设置位操作
System.out.println(b1.cardinality());//7
System.out.println(b2.isEmpty());//false
b2.clear();
System.out.println(b2.isEmpty());//true
System.out.println(b1.intersects(b3));//true
//大小操作
System.out.println(b1.size());//64
System.out.println(b1.length());//16=15+1
//查找
System.out.println(b1.nextSetBit(9));//9
System.out.println(b1.nextClearBit(9));//16
System.out.println(b1.previousSetBit(20));//15
System.out.println(b1.previousClearBit(15));//8
//类型转化操作
//byte[] b=b1.toByteArray();
//long[] l=b1.toLongArray();
}
}
/**
* 借助BitSet使用筛选法查找指定范围内的素数
* @param limit 最大正数
*/
public static void searchPrime(int limit){
BitSet bs=new BitSet(limit+1);
//约定:不是素数的在BitSet中将相应的位设置为true
int size=bs.size();
bs.set(1);
for(int i=4;i<size;i+=2)
bs.set(i);//偶数均不是素数
int finalBit=(int)Math.sqrt(size);
for(int i=2;i<finalBit;i++)
for(int j=2*i;j<size;j+=i)
bs.set(j);
int cout=0;
for(int i=1;i<size;i++){
if(!bs.get(i)){
System.out.printf("%5d",i);
if(++cout==0)
System.out.println();
}
}
System.out.println();
}
/**
* 判断一个字符串使用了哪些字符,输出格式为[字符序列]
* @param s 指定的字符串
* @return 字符串使用的字符序列
*/
public static String whichChars(String s){
BitSet bs=new BitSet();
//字符被使用,则将索引等于字符ASCII值的位置设置为true
for(int i=0;i<s.length();i++)
bs.set(s.charAt(i));
StringBuffer sb=new StringBuffer();
//输出格式化
sb.append('[');
int len=bs.length();
for(int i=0;i<len;i++)
if(bs.get(i))
sb.append((char)i);
sb.append(']');
return sb.toString();
}
/**
* 多哈希函数映射的快速查找算法,使用BitSet实现
* 应用在一些需要快速判断某个元素是否属于集合,
* 但是并不严格要求100%正确的场合,实现大数据处理。
* 应用场景包括:爬虫中url的存储。
*
Bloom Filter实现原理:
1.创建BitSet,所有位初始为false,选择k个哈希函数
2.将插入值运用k个哈希函数映射到k个二进制位,将其设为true
3.如果k个二进制为中有一个有false,则表示原纪录未被加入过;
如果k个二进制位都有true,则”认为“原纪录已被纪录过,
但是实际上不能100%确定(false positive)。
* @author Sking
*/
package bitset;
import java.util.BitSet;
public class BloomFilter {
/* BitSet初始分配2^24个bit */
private static final int DEFAULT_SIZE = 1 << 25;
/* 不同哈希函数的种子,一般应取质数 */
private static final int[] seeds = new int[] { 5, 7, 11, 13, 31, 37, 61 };
private BitSet bits = new BitSet(DEFAULT_SIZE);
/* 哈希函数对象 */
private SimpleHash[] func = new SimpleHash[seeds.length];
public BloomFilter() {
for (int i = 0; i < seeds.length; i++) {
func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);
}
}
// 将字符串标记到bits中
public void add(String value) {
for (SimpleHash f : func) {
bits.set(f.hash(value), true);
}
}
// 判断字符串是否已经被bits标记
public boolean contains(String value) {
if (value == null) {
return false;
}
boolean ret = true;
for (SimpleHash f : func) {
//如果出现一次的bits.get(f.hash(value))为false,则原纪录未被加入过
ret = ret && bits.get(f.hash(value));
}
return ret;
}
/* 哈希函数类,可修改哈希函数,实现更好的优化 */
public static class SimpleHash {
private int cap;//容量
private int seed;//种子
public SimpleHash(int cap, int seed) {
this.cap = cap;
this.seed = seed;
}
// hash函数,采用简单的加权和hash
public int hash(String value) {
int result = 0;
int len = value.length();
for (int i = 0; i < len; i++) {
result = seed * result + value.charAt(i);
}
return (cap - 1) & result;//截取加权的低log2(cap)位
}
}
}
java.util.BitSet
public class BitSet extends Object implements Cloneable, Serializable
——按需增长的位向量。默认情况下,set 中所有位的初始值都是 false。每个
bitset都包含若干设置位(值为true的位)。
构造函数
BitSet()
BitSet(int nbits)
普通方法
——1.清除位
void clear()
void clear(int bitIndex)
void clear(int fromIndex,int toIndex)
——分别将全部位| 指定区间内的位(不包括toIndex)| 指定位设置为false
——2.翻转位
void flip(int bitIndex)
void flip(int fromIndex,int toIndex)
——将指定位| 指定区间内的位翻转
——3.设置位
void set(int bitIndex)
void set(int bitIndex,boolean value)
void set(int fromIndex,int toIndex)
void set(int fromIndex,int toIndex,boolean value)
——将指定位| 指定区间内的位设置为指定boolean值,没有指定则为true
——4.获取位
boolean get(int bitIndex)
BitSet get(int fromIndex,int toIndex)
——获取指定位| 指定区间内的位集
int nextSetBit|previousSetBit(int fromIndex)
——从指定位开始查找下一个|前一个true的位索引,没有返回-1
int nextClearBit|previousClearBit(int fromIndex)
——从指定位开始查找下一个|前一个false的位索引,没有返回-1
——5.位集操作《改变的是当前BitSet,而不是参数BitSet》
void and(BitSet set) //与
void or(BitSet set) //或
void xor(BitSet set) //异或
void andNot(BitSet set) //不是与非操作
——清除此 BitSet 中所有的位,其相应的位在指定的 BitSet 中已设置。
——6.设置位操作
int cardinality()
——位集中设置位的个数
boolean isEmpty()
——如果位集中没有设置位,则返回true
boolean intersects(BitSet set)
——如果两个位集中存在同一个位置均为设置位则返回true
——7.大小操作
int size() //实际分配空间
int length() //逻辑大小,最高设置位的索引加1
——8.打印操作
String toString()
——格式:{设置为true的位索引列表,用,分隔}