bitmap是很經常使用的數據結構,好比用於Bloom Filter中、用於無重複整數的排序等等。bitmap一般基於數組來實現,數組中每一個元素能夠當作是一系列二進制數,全部元素組成更大的二進制集合。對於Python來講,整數類型默認是有符號類型,因此一個整數的可用位數爲31位。python
bitmap是用於對每一位進行操做。舉例來講,一個Python數組包含4個32位有符號整型,則總共可用位爲4 * 31 = 124位。若是要在第90個二進制位上操做,則要先獲取到操做數組的第幾個元素,再獲取相應的位索引,而後執行操做。shell
上圖所示爲一個32位整型,在Python中默認是有符號類型,最高位爲符號位,bitmap不能使用它。左邊是高位,右邊是低位,最低位爲第0位。數組
首先須要初始化bitmap。拿90這個整數來講,由於單個整型只能使用31位,因此90除以31並向上取整則可得知須要幾個數組元素。代碼以下:數據結構
#!/usr/bin/env python #coding: utf8 class Bitmap(object): def __init__(self, max): self.size = int((max + 31 - 1) / 31) #向上取整 if __name__ == '__main__': bitmap = Bitmap(90) print '須要 %d 個元素。' % bitmap.size
$ python bitmap.py 須要 3 個元素。
肯定了數組大小後,也就能夠建立這個數組了。若是要將一個整數保存進這個數組,首先須要知道保存在這個數組的第幾個元素之上,而後要知道是在這個元素的第幾位上。所以計算索引分爲:
app
計算在數組中的索引測試
計算在數組元素中的位索引spa
計算在數組中的索引實際上是跟以前計算數組大小是同樣的。只不過以前是對最大數計算,如今換成任一須要存儲的整數。可是有一點不一樣,計算在數組中的索引是向下取整,因此須要修改calcElemIndex方法的實現。代碼改成以下:
code
#!/usr/bin/env python #coding: utf8 class Bitmap(object): def __init__(self, max): self.size = self.calcElemIndex(max, True) self.array = [0 for i in range(self.size)] def calcElemIndex(self, num, up=False): '''up爲True則爲向上取整, 不然爲向下取整''' if up: return int((num + 31 - 1) / 31) #向上取整 return num / 31 if __name__ == '__main__': bitmap = Bitmap(90) print '數組須要 %d 個元素。' % bitmap.size print '47 應存儲在第 %d 個數組元素上。' % bitmap.calcElemIndex(47)
$ python bitmap.py 數組須要 3 個元素。 47 應存儲在第 1 個數組元素上。
因此獲取最大整數很重要,不然有可能建立的數組容納不下某些數據。
排序
數組元素中的位索引能夠經過取模運算來獲得。令需存儲的整數跟31取模便可獲得位索引。代碼改成以下:
索引
#!/usr/bin/env python #coding: utf8 class Bitmap(object): def __init__(self, max): self.size = self.calcElemIndex(max, True) self.array = [0 for i in range(self.size)] def calcElemIndex(self, num, up=False): '''up爲True則爲向上取整, 不然爲向下取整''' if up: return int((num + 31 - 1) / 31) #向上取整 return num / 31 def calcBitIndex(self, num): return num % 31 if __name__ == '__main__': bitmap = Bitmap(90) print '數組須要 %d 個元素。' % bitmap.size print '47 應存儲在第 %d 個數組元素上。' % bitmap.calcElemIndex(47) print '47 應存儲在第 %d 個數組元素的第 %d 位上。' % (bitmap.calcElemIndex(47), bitmap.calcBitIndex(47),)
$ python bitmap.py 數組須要 3 個元素。 47 應存儲在第 1 個數組元素上。 47 應存儲在第 1 個數組元素的第 16 位上。
別忘了是從第0位算起哦。
二進制位默認是0,將某位置1則表示在此位存儲了數據。代碼改成以下:
#!/usr/bin/env python #coding: utf8 class Bitmap(object): def __init__(self, max): self.size = self.calcElemIndex(max, True) self.array = [0 for i in range(self.size)] def calcElemIndex(self, num, up=False): '''up爲True則爲向上取整, 不然爲向下取整''' if up: return int((num + 31 - 1) / 31) #向上取整 return num / 31 def calcBitIndex(self, num): return num % 31 def set(self, num): elemIndex = self.calcElemIndex(num) byteIndex = self.calcBitIndex(num) elem = self.array[elemIndex] self.array[elemIndex] = elem | (1 << byteIndex) if __name__ == '__main__': bitmap = Bitmap(90) bitmap.set(0) print bitmap.array
$ python bitmap.py [1, 0, 0]
由於從第0位算起,因此如須要存儲0,則須要把第0位置1。
將某位置0,也即丟棄已存儲的數據。代碼以下:
#!/usr/bin/env python #coding: utf8 class Bitmap(object): def __init__(self, max): self.size = self.calcElemIndex(max, True) self.array = [0 for i in range(self.size)] def calcElemIndex(self, num, up=False): '''up爲True則爲向上取整, 不然爲向下取整''' if up: return int((num + 31 - 1) / 31) #向上取整 return num / 31 def calcBitIndex(self, num): return num % 31 def set(self, num): elemIndex = self.calcElemIndex(num) byteIndex = self.calcBitIndex(num) elem = self.array[elemIndex] self.array[elemIndex] = elem | (1 << byteIndex) def clean(self, i): elemIndex = self.calcElemIndex(i) byteIndex = self.calcBitIndex(i) elem = self.array[elemIndex] self.array[elemIndex] = elem & (~(1 << byteIndex)) if __name__ == '__main__': bitmap = Bitmap(87) bitmap.set(0) bitmap.set(34) print bitmap.array bitmap.clean(0) print bitmap.array bitmap.clean(34) print bitmap.array
$ python bitmap.py [1, 8, 0] [0, 8, 0] [0, 0, 0]
清0和置1是互反操做。
判斷某位是否爲1是爲了取出以前所存儲的數據。代碼以下:
#!/usr/bin/env python #coding: utf8 class Bitmap(object): def __init__(self, max): self.size = self.calcElemIndex(max, True) self.array = [0 for i in range(self.size)] def calcElemIndex(self, num, up=False): '''up爲True則爲向上取整, 不然爲向下取整''' if up: return int((num + 31 - 1) / 31) #向上取整 return num / 31 def calcBitIndex(self, num): return num % 31 def set(self, num): elemIndex = self.calcElemIndex(num) byteIndex = self.calcBitIndex(num) elem = self.array[elemIndex] self.array[elemIndex] = elem | (1 << byteIndex) def clean(self, i): elemIndex = self.calcElemIndex(i) byteIndex = self.calcBitIndex(i) elem = self.array[elemIndex] self.array[elemIndex] = elem & (~(1 << byteIndex)) def test(self, i): elemIndex = self.calcElemIndex(i) byteIndex = self.calcBitIndex(i) if self.array[elemIndex] & (1 << byteIndex): return True return False if __name__ == '__main__': bitmap = Bitmap(90) bitmap.set(0) print bitmap.array print bitmap.test(0) bitmap.set(1) print bitmap.test(1) print bitmap.test(2) bitmap.clean(1) print bitmap.test(1)
$ python bitmap.py [1, 0, 0] True True False False
接下來實現一個不重複數組的排序。已知一個無序非負整數數組的最大元素爲879,請對其天然排序。代碼以下:
#!/usr/bin/env python #coding: utf8 class Bitmap(object): def __init__(self, max): self.size = self.calcElemIndex(max, True) self.array = [0 for i in range(self.size)] def calcElemIndex(self, num, up=False): '''up爲True則爲向上取整, 不然爲向下取整''' if up: return int((num + 31 - 1) / 31) #向上取整 return num / 31 def calcBitIndex(self, num): return num % 31 def set(self, num): elemIndex = self.calcElemIndex(num) byteIndex = self.calcBitIndex(num) elem = self.array[elemIndex] self.array[elemIndex] = elem | (1 << byteIndex) def clean(self, i): elemIndex = self.calcElemIndex(i) byteIndex = self.calcBitIndex(i) elem = self.array[elemIndex] self.array[elemIndex] = elem & (~(1 << byteIndex)) def test(self, i): elemIndex = self.calcElemIndex(i) byteIndex = self.calcBitIndex(i) if self.array[elemIndex] & (1 << byteIndex): return True return False if __name__ == '__main__': MAX = 879 suffle_array = [45, 2, 78, 35, 67, 90, 879, 0, 340, 123, 46] result = [] bitmap = Bitmap(MAX) for num in suffle_array: bitmap.set(num) for i in range(MAX + 1): if bitmap.test(i): result.append(i) print '原始數組爲: %s' % suffle_array print '排序後的數組爲: %s' % result
$ python bitmap.py 原始數組爲: [45, 2, 78, 35, 67, 90, 879, 0, 340, 123, 46] 排序後的數組爲:[0, 2, 35, 45, 46, 67, 78, 90, 123, 340, 879]
bitmap實現了,則利用其進行排序就很是簡單了。其它語言也一樣能夠實現bitmap,但對於靜態類型語言來講,好比C/Golang這樣的語言,由於能夠直接聲明無符號整型,因此可用位就變成32位,只需將上述代碼中的31改爲32便可,這點請你們注意。