Python 实现类似C++的bitset类


C++ 的 bitset 和 Java 的 BitSet 在位操作中都十分方便和强大,能够极大地节省内存,提高操作效率。遗憾的是,Python 竟然没有提供类似的类或模块。不过利用 Python 本身的强大能力,实现一个类似的 bitset 类,十分容易,下面我们就来纯手工打造一个属于自己的 Python 的 BitSet 类。本文抛砖引玉,在实际应用中,需要对异常进行处理,例如输入的位置不合法等。好了,不不多说,直接上实现代码

 

Python的 BitSet 类实现

 

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C)  2015 By Thomas Hu.  All rights reserved.

@author : Thomas Hu
@version: 1.0
@created: 2015-4-24
'''
import array

class BitSet(object):
    # from low to high "00000001 00000010 00000011", the array is [1, 2, 3]
    def __init__(self, capacity):
        #"B"类型相当于 C 语言的 unsigned char, 即占用1byte(8位),所以size大小设置为8
        self.unit_size = 8
        self.unit_count = int((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 count(self):
        #置为 1 的位的个数
        c = 0
        for a in self.arr:
            while a > 0:
                if a & 1:
                    c += 1
                a = a>>1
        return c


    def size(self):
        #所有位的个数
        return self.unit_count * self.unit_size

    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 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 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)
                
    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

def test():
    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()

    

        
if __name__ == "__main__":
    test()
    
    

 

测试函数的输出结果

 

 

>>> 
size= 24
binstr= [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...
False True True

all() test...
False False True

none() test...
True False False

flip() test...
[00000000,00000000,00000000] [11111111,11111111,11111111]
[10111111,11111111,11111111] [01000000,00000000,00000000]
>>> 


 

 

 

评论关闭