1. 程式人生 > >點陣圖和雜湊切分的大資料處理

點陣圖和雜湊切分的大資料處理

點陣圖是一個數組的每個資料的每個二進位制位表示一個數據,0表示資料不存在,1表示資料存在;

在現實生活中,大資料的處理十分的常見;比如說,給40億個不重複的無符號整數,沒排過序,如何快速判斷一個數是否在這40億個數中?

要解決這個問題,我們首先想到的是先排序,在進行二分查詢,很容易就可以判斷成功。但是排序並不好排,40億個資料,讓我們來算一算需要多少的記憶體,40億*4位元組 =  4G*4 = 16G;一般的電腦都是4G,8G;一次處理16G的資料顯然是不可能了;這就需要用點陣圖來解決這類的問題了;

要表示40億個資料,一個數據4個位元組,32個二進位制位,用一個二進位制位來表示一個數是否存在的狀態,這就需要500M左右的記憶體;顯然這是可以接受的;具體看下圖:

實現程式碼如下

//點陣圖
class BitSet
{
public:
	BitSet(const size_t range)
	{
		_a.resize((range>>5) + 1);
	}

	void Set(size_t num)  //將num記錄;
	{
		size_t index = num >> 5;
		size_t pos = num % 32;

		_a[index] |= (1 << pos);
	}

	void Reset(size_t num)  //刪除num記錄
	{
		size_t index = num >> 5;
		size_t pos = num % 32;

		_a[index] &= ~(1 << pos);
	}

	bool Test(size_t num) //判斷num是否存在;
	{
		size_t index = num >> 5;
		size_t pos = num % 32;

		//判斷這這個位,0不存在,1存在;

		return _a[index] & (1 << pos);
	}


protected:
	vector<int> _a;
};
解決上述問題的測試用例:
void TestBitSet()
{
	BitSet bs(-1); //-1轉換後就是整數表示的最大範圍;
	bs.Set(1);
	bs.Set(3);
	bs.Set(4);
	bs.Set(8);
        //.... 向後的40億資料
	cout << bs.Test(1) << endl;
	cout << bs.Test(10) << endl;
}
讓我們繼續深入,看看另外一個問題:

給一個超過100G大小的log file,log中存著ip地址,設計演算法找到出現次數最多的IP地址?

一次處理100G,計算機想想就壓力巨大,我們可以將其劃分位計算機能處理的大小進行處理,比如以1G為單位劃分位100份,一份一份進行處理,就可達到目的,但是怎麼劃分是個難題;

第一種思路:可以將100G等分劃分位100份,每一份單獨處理,但是這個會遇到一個問題,有些想同的IP地址是在不同的等分塊中,統計的結果不是正確的結果;

第二種思路:利用雜湊切分,可以劃分成100份,重點是使相同IP進入一個編號相同的小檔案;這就避免了相同IP地址分散在不同小檔案的問題;