[从头学数学] 第253节 Python实现数据结构:比特集(BitSet)

来源:互联网 发布:韩国人看中国知乎 编辑:程序博客网 时间:2024/05/17 06:38
剧情提要:
阿伟看到了一本比较有趣的书,是关于《计算几何》的,2008年由北清派出版。很好奇
它里面讲了些什么,就来看看啦。


正剧开始:
星历2016年08月01日 10:17:09, 银河系厄尔斯星球中华帝国江南行省。

[工程师阿伟]正在和[机器小伟]一起研究[计算几何]]。





Python的实现:

<span style="font-size:18px;">#### @usage   比特集# @author  mw# @date    2016年08月01日  星期一  08:06:58 # @param# @return####class BitSet(object):    # from low to high "00000001 00000010 00000011", the array is [1, 2, 3]    def __init__(self, capacity = 64):                #"B"类型相当于 C 语言的 unsigned char, 即占用1byte(8位),所以size大小设置为8        self.unit_size = 8        self.unit_count = abs(math.floor((capacity + self.unit_size - 1) / self.unit_size));        self.capacity = capacity        self.arr = array.array("B", [0] * self.unit_count)     def any(self):        #是否存在置为 1 的位        for a in self.arr:            if a != 0:                return True        return False     def all(self):        #是否所有位都为 1, 即是否存在置为 0 的位        t = (1 << self.unit_size) - 1        for a in self.arr:            if (a & t) != t:                return False        return True          def none(self):        #是否所有位都为 0,即是否不存在置为 1 的位        for a in self.arr:            if a != 0:                return False        return True    #所有位为零为真    def isEmpty(self):        return self.none();    #至少一位为1,返回真    def intersects(self):        return self.any();    #位的数量    def length():        return self.size();    def __len__():        return self.size();    def size(self):        #所有位的个数        return self.unit_count * self.unit_size             def count(self):        #置为 1 的位的个数        c = 0        for a in self.arr:            while a > 0:                if a & 1:                    c += 1                a = a>>1        return c      def get(self, pos):        #获取第 pos 位的值        index = int(pos / self.unit_size)        offset = (self.unit_size - (pos - index * self.unit_size) - 1) % self.unit_size        return (self.arr[index] >> offset) & 1    #寻找下一个零位    def nextClearBit(self, startIndex = 0):        for i in range(startIndex+1, self.size()):            if self.get(i) == 0:                return i;        return -1;    #寻找下一个非零位    def nextSetBit(self, startIndex = 0):        for i in range(startIndex+1, self.size()):            if self.get(i) == 1:                return i;        return -1;             def test(self, pos):        #判断第 pos 位的值是否为 1        if self.get(pos):            return True        return False      def set(self, pos=-1):        #设置第 pos 位的值为 1,若 pos 为 -1, 则所有位都置为 1        if pos >= 0:            index = int(pos / self.unit_size)            offset = (self.unit_size - (pos - index * self.unit_size) - 1) % self.unit_size            self.arr[index] = (self.arr[index]) | (1 << offset)        else:            t = (1 << self.unit_size) - 1            for i in range(self.unit_count):                self.arr[i] = self.arr[i] | t                      def reset(self, pos=-1):        #设置第 pos 位的值为 0,若 pos 为 -1, 则所有位都置为 0        if pos >= 0:            index = int(pos / self.unit_size)            offset = (self.unit_size - (pos - index * self.unit_size) - 1) % self.unit_size            x = (1 << offset)            self.arr[index] = (self.arr[index]) & (~x)        else:            for i in range(self.unit_count):                self.arr[i] = 0     #所有位清零    def clear(self):        self.reset(-1);    #    def __getitem__(self, idx):        if idx < 0 or idx >= self.size():            raise IndexError("index out of range.");        return self.get(idx);    def __setitem__(self, idx, val):        if idx < 0 or idx >= self.size():            raise IndexError("index out of range.");        if (val == 0):            self.reset(idx);        elif(val == 1):            self.set(idx);    #非操作    def flip(self, pos=-1):        #把第 pos 位的值取反,若 pos 为 -1, 则所有位都取反        if pos >= 0:            if self.get(pos):                self.reset(pos)            else:                self.set(pos)        else:            for i in range(self.unit_count):                self.arr[i] = ~self.arr[i] + (1 << self.unit_size)          #两个bitset的按位与操作    def andOp(self, otherbit):        if type(self) != type(otherbit):             raise TypeError("and Op undefined for " + str(type(self)) + " + " + str(type(other)))        size_1 = self.size();        size_2 = otherbit.size();        minsize = min(size_1, size_2);        #如果比特集是从高位到低位排列,而操作应该是低位对齐        #所以应该是逆序迭代,但这种方式在两个比特集位数不等时会有问题        #所以还是默认比特集是小头序,即低字节先读取        #这样这个类设置数据时就是默认把低位设满        for i in range(minsize):            a = self.get(i);            b = otherbit.get(i);            if (a & b == 1):                self.set(i);            else:                self.reset(i);    #两个bitset的按位或操作    def orOp(self, otherbit):        if type(self) != type(otherbit):             raise TypeError("or Op undefined for " + str(type(self)) + " + " + str(type(other)))        size_1 = self.size();        size_2 = otherbit.size();        minsize = min(size_1, size_2);        #如果比特集是从高位到低位排列,而操作应该是低位对齐        #所以应该是逆序迭代,但这种方式在两个比特集位数不等时会有问题        #所以还是默认比特集是小头序,即低字节先读取        #这样这个类设置数据时就是默认把低位设满        for i in range(minsize):            a = self.get(i);            b = otherbit.get(i);            if (a | b == 1):                self.set(i);            else:                self.reset(i);    #两个bitset的按位异或操作    def xorOp(self, otherbit):        if type(self) != type(otherbit):             raise TypeError("xor Op undefined for " + str(type(self)) + " + " + str(type(other)))        size_1 = self.size();        size_2 = otherbit.size();        minsize = min(size_1, size_2);        #如果比特集是从高位到低位排列,而操作应该是低位对齐        #所以应该是逆序迭代,但这种方式在两个比特集位数不等时会有问题        #所以还是默认比特集是小头序,即低字节先读取        #这样这个类设置数据时就是默认把低位设满        for i in range(minsize):            a = self.get(i);            b = otherbit.get(i);            if (a != b):                self.set(i);            else:                self.reset(i);    #浅拷贝,重复调用BitSet中对象    def clone(self, otherbit):        self.unit_size = otherbit.unit_size;        self.unit_count = otherbit.unit_count;        self.capacity = otherbit.capacity;        self.arr = otherbit.arr;       #比特集信息显示    def binstr(self):        b = ""        for a in self.arr:            t = bin(a)            b += "0" * (self.unit_size - len(t) + 2) + t + ","        return "[" + b.replace("0b", "").strip(",") + "]"     def show(self):        return self.arr                      #类对象的hash码    def hashCode(self):        #return hash(str(self.show()));        return hash(self);</span>


用例1:

<span style="font-size:18px;">def main():    #计时开始    startTime = time.clock();    b = BitSet(20)    print("size=", b.size())    print("binstr=", b.binstr(), b.show())    # Set first block test    b.set(0)    print("b.set(0), binstr=", b.binstr(), b.show())    b.reset()    b.set(1)    print("b.set(1), binstr=", b.binstr(), b.show())     # Set second block test    b.reset()    b.set(7)    print("b.set(7), binstr=", b.binstr(), b.show())    b.reset()    b.set(8)    print("b.set(8), binstr=", b.binstr(), b.show())    b.reset()    b.set(9)    print("b.set(9), binstr=", b.binstr(), b.show())     # any test    print("\nany() test...")    b.reset()    print(b.any())    b.set(0)    print(b.any())    b.set()    print(b.any())     # all test    print("\nall() test...")    b.reset()    print(b.all())    b.set(0)    print(b.all())    b.set()    print(b.all())      # none test    print("\nnone() test...")    b.reset()    print(b.none())    b.set(0)    print(b.none())    b.set()    print(b.none())      print("\nflip() test...")    b.reset()    print(b.binstr())    b.flip()    print(b.binstr())    b.reset(1)    print(b.binstr())    b.flip()    print(b.binstr())             #计时结束    endTime = time.clock();    #打印结果    print('操作用时:{0:.3e} s'.format(endTime-startTime));>>> size= 24binstr= [00000000,00000000,00000000] array('B', [0, 0, 0])b.set(0), binstr= [10000000,00000000,00000000] array('B', [128, 0, 0])b.set(1), binstr= [01000000,00000000,00000000] array('B', [64, 0, 0])b.set(7), binstr= [00000001,00000000,00000000] array('B', [1, 0, 0])b.set(8), binstr= [00000000,10000000,00000000] array('B', [0, 128, 0])b.set(9), binstr= [00000000,01000000,00000000] array('B', [0, 64, 0])any() test...FalseTrueTrueall() test...FalseFalseTruenone() test...TrueFalseFalseflip() test...[00000000,00000000,00000000][11111111,11111111,11111111][10111111,11111111,11111111][01000000,00000000,00000000]操作用时:9.676e-02 s>>> </span>


用例2:

<span style="font-size:18px;">def main():    #计时开始    startTime = time.clock();    b_1 = BitSet(16)    b_2 = BitSet(16)    for i in range(16):        if (i%2 == 0):            b_1.set(i);        if (i%5 != 0):            b_2.set(i);    print("b_1: ", b_1.binstr(), b_1.show());    print("b_2: ", b_2.binstr(), b_2.show());    #AND操作    b_2.andOp(b_1);    print("after and, b_2 = ", b_2.binstr(), b_2.show());        #OR操作    b_2.orOp(b_1);    print("after or, b_2 = ", b_2.binstr(), b_2.show());    #XOR操作    b_2.xorOp(b_1);    print("after xor, b_2 = ", b_2.binstr(), b_2.show());    #clone操作    b_3 = BitSet(8);    b_3.clone(b_2);    print(b_3.binstr(), b_3.show());        #XOR操作    b_2.xorOp(b_1);    print("after xor, b_2 = ", b_2.binstr(), b_2.show());    print(b_3.binstr(), b_3.show());    print(b_2.hashCode(), b_3.hashCode());    b_3.clone(b_1);    print(b_1.hashCode(), b_3.hashCode());    print(b_1.show());    print(b_3.binstr(), b_3.nextSetBit(5));               #计时结束    endTime = time.clock();    #打印结果    print('操作用时:{0:.3e} s'.format(endTime-startTime));>>> b_1:  [10101010,10101010] array('B', [170, 170])b_2:  [01111011,11011110] array('B', [123, 222])after and, b_2 =  [00101010,10001010] array('B', [42, 138])after or, b_2 =  [10101010,10101010] array('B', [170, 170])after xor, b_2 =  [00000000,00000000] array('B', [0, 0])[00000000,00000000] array('B', [0, 0])after xor, b_2 =  [10101010,10101010] array('B', [170, 170])[10101010,10101010] array('B', [170, 170])1094709 10853711094705 1085371array('B', [170, 170])[10101010,10101010] 6操作用时:6.627e-02 s</span>

Java中有现成的类,可以直接使用:

<span style="font-size:18px;">import java.util.BitSet;public class BitSetDemo {  public static void main(String args[]) {     BitSet bits1 = new BitSet(16);     BitSet bits2 = new BitSet(16);           // set some bits     for(int i=0; i<16; i++) {        if((i%2) == 0) bits1.set(i);        if((i%5) != 0) bits2.set(i);     }     System.out.println("Initial pattern in bits1: ");     System.out.println(bits1);     System.out.println("Initial pattern in bits2: ");     System.out.println(bits2);     // AND bits     bits2.and(bits1);     System.out.println("bits2 AND bits1: ");     System.out.println(bits2);     // OR bits     bits2.or(bits1);     System.out.println("bits2 OR bits1: ");     System.out.println(bits2);     // XOR bits     bits2.xor(bits1);     System.out.println("bits2 XOR bits1: ");     System.out.println(bits2);  }}//结果:Initial pattern in bits1:{0, 2, 4, 6, 8, 10, 12, 14}Initial pattern in bits2:{1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14}bits2 AND bits1:{2, 4, 6, 8, 12, 14}bits2 OR bits1:{0, 2, 4, 6, 8, 10, 12, 14}bits2 XOR bits1:{}</span>

彩蛋:



本节到此结束,欲知后事如何,请看下回分解。

0 0