Java Bitset类
一个Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。这和位向量(vector of bits)比较类似。
这是一个传统的类,但它在Java 2中被完全重新设计。
BitSet定义了两个构造方法。
第一个构造方法创建一个默认的对象:
BitSet()
第二个方法允许用户指定初始大小。所有位初始化为0。
BitSet(int size)
BitSet中实现了Cloneable接口中定义的方法如下表所列:
| 序号 | 方法描述 |
|---|---|
| 1 | void
and(BitSet bitSet) 对此目标位 set 和参数位 set 执行逻辑与操作。 |
| 2 | void
andNot(BitSet bitSet) 清除此 BitSet 中所有的位,其相应的位在指定的 BitSet 中已设置。 |
| 3 | int
cardinality( ) 返回此 BitSet 中设置为 true 的位数。 |
| 4 | void
clear( ) 将此 BitSet 中的所有位设置为 false。 |
| 5 | void
clear(int index) 将索引指定处的位设置为 false。 |
| 6 | void
clear(int startIndex, int
endIndex) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 false。 |
| 7 | Object
clone( ) 复制此 BitSet,生成一个与之相等的新 BitSet。 |
| 8 | boolean
equals(Object bitSet) 将此对象与指定的对象进行比较。 |
| 9 | void
flip(int index) 将指定索引处的位设置为其当前值的补码。 |
| 10 | void
flip(int startIndex, int
endIndex) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的每个位设置为其当前值的补码。 |
| 11 | boolean
get(int index) 返回指定索引处的位值。 |
| 12 | BitSet
get(int startIndex, int
endIndex) 返回一个新的 BitSet,它由此 BitSet 中从 fromIndex(包括)到 toIndex(不包括)范围内的位组成。 |
| 13 | int
hashCode( ) 返回此位 set 的哈希码值。 |
| 14 | boolean
intersects(BitSet
bitSet) 如果指定的 BitSet 中有设置为 true 的位,并且在此 BitSet 中也将其设置为 true,则返回 ture。 |
| 15 | boolean
isEmpty( ) 如果此 BitSet 中没有包含任何设置为 true 的位,则返回 ture。 |
| 16 | int
length( ) 返回此 BitSet 的"逻辑大小":BitSet 中最高设置位的索引加 1。 |
| 17 | int
nextClearBit(int
startIndex) 返回第一个设置为 false 的位的索引,这发生在指定的起始索引或之后的索引上。 |
| 18 | int
nextSetBit(int startIndex) 返回第一个设置为 true 的位的索引,这发生在指定的起始索引或之后的索引上。 |
| 19 | void
or(BitSet bitSet) 对此位 set 和位 set 参数执行逻辑或操作。 |
| 20 | void
set(int index) 将指定索引处的位设置为 true。 |
| 21 | void
set(int index, boolean v) 将指定索引处的位设置为指定的值。 |
| 22 | void
set(int startIndex, int
endIndex) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 true。 |
| 23 | void
set(int startIndex, int endIndex, boolean
v) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为指定的值。 |
| 24 | int
size( ) 返回此 BitSet 表示位值时实际使用空间的位数。 |
| 25 | String
toString( ) 返回此位 set 的字符串表示形式。 |
| 26 | void
xor(BitSet bitSet) 对此位 set 和位 set 参数执行逻辑异或操作。 |
java.util.BitSet 存数海量数据时的一个途径
java.util.BitSet可以按位存储。
计算机中一个字节(byte)占8位(bit),我们java中数据至少按字节存储的,
比如一个int占4个字节。
如果遇到大的数据量,这样必然会需要很大存储空间和内存。
如何减少数据占用存储空间和内存可以用算法解决。
java.util.BitSet就提供了这样的算法。
比如有一堆数字,需要存储,source=[3,5,6,9]
用int就需要4*4个字节。
java.util.BitSet可以存true/false。
如果用java.util.BitSet,则会少很多,其原理是:
1,先找出数据中最大值maxvalue=9
2,声明一个BitSet bs,它的size是maxvalue+1=10
3,遍历数据source,bs[source[i]]设置成true.
最后的值是:
(0为false;1为true)
bs [0,0,0,1,0,1,1,0,0,1]
3, 5,6, 9
这样一个本来要int型需要占4字节共32位的数字现在只用了1位!
比例32:1
这样就省下了很大空间。
看看测试例子
package com;
import java.util.BitSet;
public class MainTestThree {
/**
* @param args
*/
public static void main(String[] args) {
BitSet bm=new BitSet();
System.out.println(bm.isEmpty()+"--"+bm.size());
bm.set(0);
System.out.println(bm.isEmpty()+"--"+bm.size());
bm.set(1);
System.out.println(bm.isEmpty()+"--"+bm.size());
System.out.println(bm.get(65));
System.out.println(bm.isEmpty()+"--"+bm.size());
bm.set(65);
System.out.println(bm.isEmpty()+"--"+bm.size());
}
}输出:
true--64
false--64
false--64
false
false--64
false--128
说明默认的构造函数声明一个64位的BitSet,值都是false。
如果你要用的位超过了默认size,它会再申请64位,而不是报错。
package com;
import java.util.BitSet;
public class MianTestFour {
/**
* @param args
*/
public static void main(String[] args) {
BitSet bm1=new BitSet(7);
System.out.println(bm1.isEmpty()+"--"+bm1.size());
BitSet bm2=new BitSet(63);
System.out.println(bm2.isEmpty()+"--"+bm2.size());
BitSet bm3=new BitSet(65);
System.out.println(bm3.isEmpty()+"--"+bm3.size());
BitSet bm4=new BitSet(111);
System.out.println(bm4.isEmpty()+"--"+bm4.size());
}
}输出:
true--64
true--64
true--128
true--128
说明你申请的位都是以64为倍数的,就是说你申请不超过一个64的就按64算,超过一个不超过
2个的就按128算。
package com;
import java.util.BitSet;
public class MainTestFive {
/**
* @param args
*/
public static void main(String[] args) {
int[] shu={2,42,5,6,6,18,33,15,25,31,28,37};
BitSet bm1=new BitSet(MainTestFive.getMaxValue(shu));
System.out.println("bm1.size()--"+bm1.size());
MainTestFive.putValueIntoBitSet(shu, bm1);
printBitSet(bm1);
}
//初始全部为false,这个你可以不用,因为默认都是false
public static void initBitSet(BitSet bs){
for(int i=0;i
bs.set(i, false);
}
}
//打印
public static void printBitSet(BitSet bs){
StringBuffer buf=new StringBuffer();
buf.append("[\n");
for(int i=0;i
if(i
buf.append(MainTestFive.getBitTo10(bs.get(i))+",");
}else{
buf.append(MainTestFive.getBitTo10(bs.get(i)));
}
if((i+1)%8==0&&i!=0){
buf.append("\n");
}
}
buf.append("]");
System.out.println(buf.toString());
}
//找出数据集合最大值
public static int getMaxValue(int[] zu){
int temp=0;
temp=zu[0];
for(int i=0;i
if(temp
temp=zu[i];
}
}
System.out.println("maxvalue:"+temp);
return temp;
}
//放值
public static void putValueIntoBitSet(int[] shu,BitSet bs){
for(int i=0;i
bs.set(shu[i], true);
}
}
//true,false换成1,0为了好看
public static String getBitTo10(boolean flag){
String a="";
if(flag==true){
return "1";
}else{
return "0";
}
}
}输出:
maxvalue:42
bm1.size()--64
[
0,0,1,0,0,1,1,0,
0,0,0,0,0,0,0,1,
0,0,1,0,0,0,0,0,
0,1,0,0,1,0,0,1,
0,1,0,0,0,1,0,0,
0,0,1,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
]
这样便完成了存值和取值。
注意它会对重复的数字过滤,就是说,一个数字出现过超过2次的它都记成1.
出现的次数这个信息就丢了。
Java Bitset和位运算
(1)BitSet类 默认情况下,set 中所有位的初始值都是 false。 |
(2) 构造函数: BitSet() or BitSet(int nbits)
(3) 一些方法
public void set(int pos): 位置pos的字位设置为true。
public void set(int bitIndex, boolean value) 将指定索引处的位设置为指定的值。
public void clear(int pos): 位置pos的字位设置为false。
public void clear() : 将此 BitSet 中的所有位设置为 false。
public int cardinality() 返回此 BitSet 中设置为 true 的位数。
public boolean get(int pos): 返回位置是pos的字位值。
public void and(BitSet other): other同该字位集进行与操作,结果作为该字位集的新值。
public void or(BitSet other): other同该字位集进行或操作,结果作为该字位集的新值。
public void xor(BitSet other): other同该字位集进行异或操作,结果作为该字位集的新值。
public void andNot(BitSet set) 清除此 BitSet 中所有的位,set - 用来屏蔽此 BitSet 的 BitSet
public int size(): 返回此 BitSet 表示位值时实际使用空间的位数。
public int length() 返回此 BitSet 的“逻辑大小”:BitSet 中最高设置位的索引加 1。
public int hashCode(): 返回该集合Hash 码, 这个码同集合中的字位值有关。
public boolean equals(Object other): 如果other中的字位同集合中的字位相同,返回true。
public Object clone() 克隆此 BitSet,生成一个与之相等的新 BitSet。
public String toString() 返回此位 set 的字符串表示形式。
(4)========================================================================
public static void main(String[] args) throws ParseException ...{
BitSet bit = new BitSet (100);
bit.set(1);
bit.set(10);
BitSet anBit = new BitSet();
anBit.set(10);
anBit.set(5);
//bit.and(anBit);
bit.or(anBit);
for(int i=0; i
...{
System.out.println(bit.get(i));
}
}results:
false
true
false
false
false
true
false
false
false
false
true
==========================================================================================
(5)Java 位运算
1.表示方法:
在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。
(l)正数的最高位为0,其余各位代表数值本身(二进制数)。
(2)对于负数,通过对该数绝对值的补码按位取反,再对整个数加1。
2.位运算符
位运算表达式由操作数和位运算符组成,实现对整数类型的二进制数进行位运算。位运算符可以分为逻辑运算符(包括~、&、|和^)及移位运算符(包括>>、<<和>>>)。
1)左移位运算符(<<)能将运算符左边的运算对象向左移动运算符右侧指定的位数(在低位补0)。
2)“有符号”右移位运算符(>>)则将运算符左边的运算对象向右移动运算符右侧指定的位数。
“有符号”右移位运算符使用了“符号扩展”:若值为正,则在高位插入0;若值为负,则在高位插入1。
3)Java也添加了一种“无符号”右移位运算符(>>>),它使用了“零扩展”:无论正负,都在高位插入0。这一运算符是C或C++没有的。
4)若对char,byte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int。
只有右侧的5个低位才会用到。这样可防止我们在一个int数里移动不切实际的位数。
若对一个long值进行处理,最后得到的结果也是long。此时只会用到右侧的6个低位,防止移动超过long值里现成的位数。
但在进行“无符号”右移位时,也可能遇到一个问题。若对byte或short值进行右移位运算,得到的可能不是正确的结果(Java 1.0和Java 1.1特别突出)。
它们会自动转换成int类型,并进行右移位。但“零扩展”不会发生,所以在那些情况下会得到-1的结果。
在进行位运算时,需要注意以下几点。
(1)>>>和>>的区别是:在执行运算时,>>>运算符的操作数高位补0,而>>运算符的操作数高位移入原来高位的值。
(2)右移一位相当于除以2,左移一位(在不溢出的情况下)相当于乘以2;移位运算速度高于乘除运算。
(3)若进行位逻辑运算的两个操作数的数据长度不相同,则返回值应该是数据长度较长的数据类型。
(4)按位异或可以不使用临时变量完成两个值的交换,也可以使某个整型数的特定位的值翻转。
(5)按位与运算可以用来屏蔽特定的位,也可以用来取某个数型数中某些特定的位。
(6)按位或运算可以用来对某个整型数的特定位的值置l。
3.位运算符的优先级
~的优先级最高,其次是<<、>>和>>>,再次是&,然后是^,优先级最低的是|。
二, 按位异或运算符^
参与运算的两个值,如果两个相应位相同,则结果为0,否则为1。即:0^0=0, 1^0=1, 0^1=1, 1^1=0
例如:10100001^00010001=10110000
0^0=0,0^1=1 0异或任何数=任何数
1^0=1,1^1=0 1异或任何数-任何数取反
任何数异或自己=把自己置0
(1)按位异或可以用来使某些特定的位翻转,如对数10100001的第2位和第3位翻转,可以将数与00000110进行按位异或运算。
10100001^00000110=10100111 //1010 0001 ^ 0x06 = 1010 0001 ^ 6
(2)通过按位异或运算,可以实现两个值的交换,而不必使用临时变量。例如交换两个整数a,b的值,可通过下列语句实现:
a=10100001,b=00000110
a=a^b; //a=10100111
b=b^a; //b=10100001
a=a^b; //a=00000110
(3)异或运算符的特点是:数a两次异或同一个数b(a=a^b^b)仍然为原值a.
三,Java 中除了二进制的表示方法:
由于数据在计算机中的表示,最终以二进制的形式存在,所以有时候使用二进制,可以更直观地解决问题。
但,二进制数太长了。比如int 类型占用4个字节,32位。比如100,用int类型的二进制数表达将是:
0000 0000 0000 0000 0110 0100
面对这么长的数进行思考或操作,没有人会喜欢。因此,C,C++,以及java中 没有提供在代码直接写二进制数的方法。
八进制数的表达方法
如何表达一个八进制数呢?如果这个数是 876,我们可以断定它不是八进制数,因为八进制数中不可能出7以上的阿拉伯数字。但如果这个数是123、是567,或12345670,那么它是八进制数还是10进制数,都有可能。
所以规定,一个数如果要指明它采用八进制,必须在它前面加上一个0, 如:123是十进制,但0123则表示采用八进制。这就是八进制数的表达方法。
现在,对于同样一个数,比如是100,我们在代码中可以用平常的10进制表达,例如在变量初始化时:
int a = 100;
我们也可以这样写:
int a = 0144; //0144是八进制的100;一个10进制数如何转成8进制。
千万记住,用八进制表达时,你不能少了最前的那个0。否则计算机会通通当成10进制。不过,有一个地方使用八进制数时,却不能使用加0,那就是我们前面学的用于表达字符的“转义符”表达法。
十六进制数的表达方法
如果不使用特殊的书写形式,16进制数也会和10进制相混。随便一个数:9876,就看不出它是16进制或10进制。
1 6 进制数必须以 0x开头。 比如 0x1表示一个16进制数。而1则表示一个十进制。另外如:0xff,0xFF,0X102A,等等。其中的x也也不区分大小写。(注意:0x中的0是数字0,而不是字母O)
以下是一些用法示例:
int a = 0x100F;
int b = 0x70 + a;
最后一点很重要,10进制数有正负之分,比如12表示正12,而-12表示负 12,;但8进制和16进制只能用达无符号的正整数,如果你在代码中里:-078,或者写:-0xF2,编译器并不把它当成一个负数。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
