在學習linux過程中,wait函數中的status參數的用法其實就如同位圖,位圖法就是bitmap的縮寫。所謂bitmap,就是用每一位來存放某種狀態,適用於大規模數據,但數據狀態又不是很多的情況。通常是用來判斷某個數據存不存在的。在STL中有一個bitset容器,其實就是位圖法。
一、先給一個很簡單的情景來引入該結構。題目如下:
加入給定40億個無符號整數,要快速判斷一個值是否在這其中,該怎麼解決?
首先我們得了解內存中各個單位之間的轉換:
通過上面的圖我們可以瞭解到40個億個整型在4G內存中如果都以整型的方式是存不下的!!也就壓根別想我們存到一個數組裏,依次遍歷一遍這種簡單粗暴的辦法了。這時候就可以利用位圖來解決這個題。先簡述一下位圖的解決方法:我們可以給每一個不同的數字在開闢的數組中拿一個位表示它在或者不在(一個位的狀態只有0或者1,剛好對應了題目中的存在或者不存在),這時候存40億個整型就被我們轉換成了存儲40億個位,再計算一下我們只需要差不多500M的空間就可以存下這40億個數字的出現狀態,最後再計算出該數字對應的那一位的狀態,如果是1則表示存在,是0則不存在。
先給出實現代碼再來一步步解釋
class MyBitMap
{
public:
MyBitMap()
{}
MyBitMap(const int& range)
{
_a.resize((range >> 3) + 1);
}
void Set(const int& x)
{
int index = (x >> 3);
int bit = x % 8;
_a[index] |= (1 << bit);
}
void Reset(const int& x)
{
int index = (x >> 3);
int bit = x % 8;
_a[index] &= ~(1 << bit);
}
bool Test(const int& x)
{
int index = (x >> 3);
int bit = x % 8;
bool res = (_a[index] >> bit) & 1;
return res;
}
private:
vector<char> _a;
};
簡單的測試一下:
梳理過程:
開闢空間:給定一個數值範圍,開闢大小爲rang / 8 +1的數組。+1的原因在於當範圍小於8時,如果不加1則數組開闢大小就爲0,那接下來的操作就會錯誤。
置1操作:給定一個數值,計算出該數字在數組中對應的下標以及在該下標中對應的位,或上1左移bit位,就完成了將該位置1的操作;
置0操作:同上,只不過需要與上~(1 << bit),就完成置0操作;
取出結果:算出對應的下標以及位後,取出該位的結果進行判斷即可。
將上面的測試用圖示的方法梳理下:
二、再給個稍微複雜一點的情景:假如還是40億個數字,我們現在要找出其中出現次數不少於三次的數字。有了上面的鋪墊,這個題就很簡單了。
思路:第一題由於只需要表示存在或不存在,一個二進制位就可以表示了。在這個題中,不少於兩次就需要使用兩位來表示:00代表沒出現過,01代表出現了一次,10表示出現了兩次,11表示出現了不少於三次,也就是大於等於3。
實現代碼:
class TwoBitMap
{
public:
TwoBitMap()
{}
TwoBitMap(const int& range)
{
//range /4
_a.resize((range >> 2) + 1);
}
void Set(const int& x)
{
int index = (x >> 2);
int bit_start = x % 4 * 2;
bool first = _a[index] & (1 << bit_start);
bool second = _a[index] & (1 << (bit_start + 1));
if (!(first && second))
_a[index] += (1 << bit_start);
}
bool Test(const int& x)
{
int index = (x >> 2);
int bit_start = x % 4 * 2;
bool first = _a[index] & (1 << bit_start);
bool second = _a[index] & (1 << (bit_start + 1));
return first && second ? true : false;
}
private:
vector<char> _a;
};