位数组
Posted pilgrim
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了位数组相关的知识,希望对你有一定的参考价值。
在处理数字有许多位时,可以使用C#中的BitArray类和BitVector32结构。BitArray类与BitVector32结构的区别是:BitArray类可以重新设置大小,对于事先不知道需要的位数,可以使用BitArray类,它可以包含很多位。BitVector32结构是基于栈的,相对于类比较快,但是它只含有32位,存储在一个整数中。
1、BitArray类
BitArray类是一个引用类型,它包含一个int数组,每32位使用一个新整数。每一个位都是一个bool值。
创建一个位数组:
//*****************创建位数组***********************
BitArray bits = new BitArray(8);//创建一个包含8位的数组 bits.SetAll(true);//将8个位都设置为true bits.Set(1, false);//将下标为1(第二个位)设置为false bits[5] = false;//将下标为5的位设置为false Console.WriteLine("Initialized: "); foreach (bool b in bits) { Console.WriteLine(b ? 1 : 0); }
如果创建一个位数组时,在构造函数中传入一个位数组,那么新创建的位数组将和参数位数组具有相同的值。在构造位数组时,可以使用字节数组、int类型数组、bool数组和位数组进行初始化构造位数组。注意:只能是数组形式。如果传入一个int类型的数字,则认为创建int长度的位的位数组。
位数组中有许多方法,如:Set()设置某个位上的值;SetAll()设置所有位上的值;Not()对所有位取反;And()、Or()、Xor()用于两个位数组之间的合并运算等方法。
2、BitVector32结构
如果事先知道需要的位数,可以使用BitVector32结构代替BitArray类。因为BitVector32是值类型的关系,所以在效率上相对较高。对于需要更多的位可以使用多个BitVector32结构或者BitArray类。
使用默认构造函数创建一个BitVector32结构,所有位都默认为false。然后创建掩码,以访问位矢量中的位。使用索引器访问对应的位,并设置相应的字段。
BitVector32 bits1 = new BitVector32(); int bit1 = BitVector32.CreateMask(); //创建掩码,运行后bit1=1; int bit2 = BitVector32.CreateMask(bit1);//创建掩码,运行后bit2=2; int bit3 = BitVector32.CreateMask(bit2);//创建掩码,运行后bit3=3; int bit4 = BitVector32.CreateMask(bit3);//创建掩码,运行后bit4=4; int bit5 = BitVector32.CreateMask(bit4);//创建掩码,运行后bit5=5; bits1[bit1] = true; bits1[bit2] = true; bits1[bit3] = false; bits1[bit4] = true; bits1[bit5] = true; Console.WriteLine(bits1);//输出为:BitVector32{00000000000000000000000000011011}
也可以自己创建掩码,一次性设置多个位。例如十六进制的abcdef与二进制的1010 1011 1100 1101 1110 1111相同。因此对于一个新创建的bits:
bits[0xabcdef] = true;//输出为:BitVector32{00000000101010111100110111101111}
IPv4中的应用:IPv4地址定义为一个4字节的数,该数存储在一个整数中。可以定义4个片段,把这个整数拆分开。在多播IP消息中,使用了几个32位的值。其中一个32位的值放在这些片段中:16位表示源号,8位表示查询器的查询内部码,3位表示查询器的健壮变量,1位表示抑制标志,保留4位。也可以自己定义位含义,以节省内存。下面的例子中,模拟接收到值0x79abcdef:
int received = 0x79abcdef; BitVector32 bits = new BitVector32(received);//bits结构为:BitVector32{01111001101010111100110111101111}
接着创建6个片段:第一个片段A需要12位,由十六进制值0xffff定义;第二个片段B需要8位;第三个片段C需要4位;第四个片段D和第五个片段E需要3位;第六个片段需要2位。除第一个片段外,其余片段皆将上一个片段作为参数传递,使得该片段从上一片段的结尾处开始。CreateSection()方法返回一个BitVector32.Section类型的值,该类型包含了该片段的偏移量和掩码:
//sections: FF EEE DDD CCCC BBBBBBBB AAAAAAAAAAAA BitVector32.Section sectionA = BitVector32.CreateSection(0xfff);
BitVector32.Section sectionB= BitVector32.CreateSection(0xff, sectionA);
BitVector32.Section sectionC = BitVector32.CreateSection(0xf, sectionB);
BitVector32.Section sectionD = BitVector32.CreateSection(0x7, sectionC);
BitVector32.Section sectionE = BitVector32.CreateSection(0x7, sectionD);
BitVector32.Section sectionF = BitVector32.CreateSection(0x3, sectionE);
把一个BitVector32.Section类型的值传递给BitVector32结构的索引器,会返回一个int,它映射到位矢量的片段上。
首先创建一个展示方法IntToBInaryString():
static string IntToBinaryString(int bits,bool removeTrailingZero) { StringBuilder builder = new StringBuilder(32); for(int i=0;i<32;i++) { if ((bits & 0x80000000) != 0) { builder.Append("1"); } else { builder.Append("0"); } bits=bits << 1; } string s = builder.ToString(); if(removeTrailingZero) { return s.TrimStart(‘0‘); } return s; }
结果显示了片段A~F的位表示:
Console.WriteLine("Section A: {0}", IntToBinaryString(bits[sectionA], true));//输出为:Section A: 110111101111 Console.WriteLine("Section B: {0}", IntToBinaryString(bits[sectionB], true));//输出为: Section B: 10111100 Console.WriteLine("Section C: {0}", IntToBinaryString(bits[sectionC], true));//输出为:Section C: 1010 Console.WriteLine("Section D: {0}", IntToBinaryString(bits[sectionD], true));//输出为:Section D: 1 Console.WriteLine("Section E: {0}", IntToBinaryString(bits[sectionE], true));//输出为:Section E: 111 Console.WriteLine("Section F: {0}", IntToBinaryString(bits[sectionF], true));//输出为:Section F: 1
以上显示结果,与最开始的整数位一一对应:
//BitVector32{ 01 111 001 1010 10111100 110111101111} //sections: FF EEE DDD CCCC BBBBBBBB AAAAAAAAAAAA
以上是关于位数组的主要内容,如果未能解决你的问题,请参考以下文章