位圖就是bitmap/bitset的縮寫。所謂bitmap,就是用每一位來存放某種狀態,適用於大規模數據,但數據狀態又不是很多的情況。通常是用來判斷某個數據存不存在的。
有一個騰訊面試題:給40億個不重複的unsigned int的整數,沒排過序的,然後再給一個數,如何快速判斷這個數是否在那40億個數當中?
這裏可以用位圖來實現。首先我們需要考慮,40億個數據需要多大的內存空間。一般計算機內存大小爲4GB,即4*2^10*2^10*2^10B,很容易得出大概500M的 空間就夠了。申請500M的內存,一個bit位代表一個unsigned int值。讀入40億個數,設置相應的bit位,讀入要查詢的數,查看相應bit位是否爲1,爲1表示存在,爲0表示不存在。
下面看程序實現
BitSet.cpp
# include<iostream> using namespace std; #include<assert.h> class BitSet{ public: BitSet(size_t N){ //構造函數 _size = N / 32 + 1; //計算需要給數組開闢的空間數 _array = new size_t[_size]; memset(_array, 0, sizeof(size_t)*_size); //初始化數組 } ~BitSet(){ //析構函數 delete[] _array; } void Set(size_t num){ //對數所在數組位置置1 size_t index = num / 32; size_t pos = num % 32; _array[index] |= (1 << (32 - pos)); } void Reset(size_t num){ //恢復初始值狀態 size_t index = num / 32; size_t pos = num % 32; _array[index] &= ~(1 << (32 - pos)); } bool Test(size_t num){ //測試是否設置成功,成功則返回設置值 size_t index = num / 32; size_t pos = num % 32; assert(index < _size); return _array[index] & (1 << (32 - pos)); } void Clear(){ //清除所有設置 memset(_array, 0, sizeof(size_t)*_size); } private: size_t* _array; size_t _size; }; void test(){ BitSet bs(100); bs.Set(50); bs.Test(50); bs.Reset(50); bs.Test(50); bs.Set(20); bs.Set(21); bs.Reset(20); bs.Clear(); } int main(){ test(); return 0; }
位圖法比較適合於這種情況,它的做法是按照集合中最大元素max創建一個長度爲max+1的新數組,然後再次掃描原數組,遇到幾就給新數組的第幾位置上1,如遇到5就給新數組的第六個元素置1,這樣下次再遇到5想置位時發現新數組的第六個元素已經是1了,這說明這次的數據肯定和以前的數據存在着重複。這種給新數組初始化時置零其後置一的做法類似於位圖的處理方法故稱位圖法。它的運算次數最壞的情況爲2N。如果已知數組的最大值即能事先給新數組定長的話效率還能提高一倍。