大數據的處理算法——BitMap算法

大數據的處理算法——BitMap算法

首先我們來看一個問題:

如何判斷一個整數是否在40億個整數之中?

當時我看到這個問題首先想到的是利用一個map或者set進行存儲(/笑哭)

但是一個整數4個字節,40億個整數就是160億個字節,需要16GB的內存(/驚訝)

如果分多次加載就需要利用到磁盤的IO,但是磁盤的IO讀取速度遠遠低於內存的讀取速度

所以是不可取的!!!

那麼可以採用分佈式的算法來實現,利用8臺計算機,每臺計算機2G內存,將數據分散到這8臺計算機中進行處理,這樣的效率就比較能夠接受。

但是還有沒有更好的方式呢?

有!!!

是什麼?

Bitmap算法!!!

Bitmap算法

首先我們來了解一下bitmap算法是個啥?

1:Bit-Map算法又名位圖算法,其原理是,使用下標代替數值或特定的意義,使用這個位爲0或者1代表特性是否存在。

2:Bit-Map算法具有效率高,節省空間的特點,適用於對大量數據進行去重,查詢等。
說簡單點

就是咱們把每個數據的狀態存在爲1,不存在爲0,利用bit字節來進行存儲,這樣大大的節約了空間!!

那麼可以簡單的聯想到BitMap的應用領域:

排序,查找,存儲一個用戶的各種標籤數據啊,用bitmap算法都是一種比較棒的方式。

那麼回到題目:

如何判斷一個整數是否在40億個整數之中?

我們來看一段代碼,當然這裏我沒用40億這麼大

我這裏用10000000,其實也很大了(/doge)

import java.util.ArrayList;
import java.util.List;

public class BitMap {

	private static final int N = 10000000;
	private int[] a = new int[N/32 + 1];
	
	/**
	 * 設置所在的bit位爲1
	 * @param n
	 */
	public void addValue(int n) {
		//int row = n / 32;
		int row = n >> 5;
		// >>相當於/2的n次方,<<相當於*2的n次方
		a[row] |= 1 << (n & 0x1F);
		//  |=是相當於a 和=後面的值做或運算然後賦值給a
		//	0x在計算機中代表16進制,F代表16 1F = 1*F + F = 32
	}
	
	/**
	 * 判斷所在bit位是否爲1
	 * @param n
	 * @return
	 */
	public boolean exits(int n) {
		int row = n >> 5;
		return (a[row] & (1 << (n & 0x1F))) != 0;
	}
	
	public void display(int row) {
		System.out.println("bitMap位圖展示");
		for(int i = 0; i < row; i++) {
			List<Integer> list = new ArrayList<Integer>();
			int temp = a[i];
			for(int j = 0; j < 32; j++) {
				list.add(temp & 1);
				temp >>= 1;
			}
			System.out.println("a["+i+"]" + list);
		}
	}
	
	public static void main(String[] args) {
		int[] num = {1,5,30,32,64,56,159,120,21,17,35,45};
		BitMap map = new BitMap();
		for(int i = 0; i < num.length; i++) {
			map.addValue(num[i]);
		}
		
		int temp = 120;
		if(map.exits(temp)) {
			System.out.println("temp:" + temp + "has already exists");
		}
		int temp2 = 131;
		if(map.exits(temp2)) {
			System.out.println("temp2:" + temp2 + " has already exists");
		}else {
			System.out.println("temp2:" + temp2 + " not has already exists");
		}
		map.display(5);
	}
}

運行結果:

temp: 120 has already exists
temp2: 131 not has already exists
bitMap位圖展示
a[0][0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
a[1][1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
a[2][1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
a[3][0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
a[4][0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

要想實現這個bitMap算法,首先我們要想明白兩點:

1.十進制如何轉化爲對應數組a中的下標

​ 解決辦法:

​ 十進制數0-31,對應在數組a[0]中,32-63對應在數組a[1]中,64-95對應在數組a[2]中………,使用

                 數學歸納分析得出結論:對於一個十進制數n,其在數組a中的下標爲:a[n/32]  

2十進制對在對應a[i]中的下標

​ 例如十進制數1在a[0]的下標爲1,十進制數31在a[0]中下標爲31,十進制數32在a[1]中下標爲0。 在

​ 十進制0-31就對應0-31,而32-63則對應也是0-31,即給定一個數n可以通過模32求得在對應數組a[i]

​ 中的下標。

那麼這裏就不能不碰到java中的位運算了

然後有關Java的位運算,我在註釋裏面寫的很詳細,可以仔細去看下(/doge)

當然

a[row] |= 1 << (n & 0x1F);
//  |=是相當於a 和=後面的值做或運算然後賦值給a
//	0x在計算機中代表16進制,F代表16 1F = 1*F + F = 32

這裏是通過移位的方式來置1的

結語

當我看到bitmap算法,我就和看到寶一樣。這個算法的優越性不言而喻了,以後編程中可以多多利用,故此記錄下來!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章