先了解一下位運算的基礎知識:
所有比特的編號方法是:從低字節的低位比特位開始,第一個bit為0,最后一個bit為 n-1。
比如,給出一個數組:int[] array = new int[4]。那么:
a[0] -- a[4] 的比特位分別為:0--31,32--63,64--95,96--127
下面我們依據一個程序探究數組比特位的編號:
public class BitNumber { public static void main(String[] args) { int[] array = new int[4]; for (int i = 0; i < array.length; i++) { array[i] = 16; } for (int i = 0; i < array.length; i++) { array[i] = array[i] >> 4; System.out.println(array[i]); } } }
結果是輸出了4個1,也就是說剛開始比特位編排為:0000 0000 0001 0000,使用位運算,使其右移了4位,變為:0000 0000 0000 0001.
利用位運算& 進行取模
位運算跟取模運算之間聯系微妙,具體可從下面的例子中看出來:
100%32;100&31
上述公式的結果是一樣的,讓我們探究一下他們的原理:
100%32 的取余運算,將取到一百減去3個32之后的余數為4。 100&31是進行按位與運算,31=0001 1111;100=0110 0100,當他們進行按位與時,大於等於32的那部分將給消去,留下的便是余數。
當然上述運算成立的條件便是 32對應位置的數必須是2的N次冪。
特定位的設置與清除
假如現在 int a = 0; 現在a的編碼全部為0,現在要將其從右往左第5個位置設置為1,然后再清除上述操作
static int a = 0; public static void main(String[] args) { a |= (1<<5); // | 按位或操作 ,雙目運算符 a = a|(1<<5); System.out.println(a); a &= ~(1<<5); // & 按位與操作,雙目運算符, ~ 按位非操作,單目運算符 System.out.println(a); }
上述運算的結果分別為32 0.
字節位置與位位置
一個int是4個字節,每個字節有32bit,我們可以將數據存儲在這些位內。比如我們要存儲100這個數,我們只需在位置100存儲一個1。將第100位置為1,也就是說最少需要有100個位置,每個位置1bit,100個位置需要12.5字節,因為一個int型是4字節,所以我們需要定義一個數組 int[4]。
現在我們要對這個數組的100位進行操作,首先要知道100在這個數組中的第幾個元素,每個數組元素都是32位,那么100所在的位置就是100/32,也就是 100>>5。然后在元素中的位置也就是:100%32,也就是100&31,也就是100&0x1F。
給一個例子:
給40億個不重復的unsigned int的整數,沒有排過序,然后再給一個數,如果快速判斷這個數是否在那40億個數當中。
因為unsigned int數據的最大范圍在在40億左右(需要40億bit),40*10^8/1024*1024*8=476,因此只需申請512M的內存空間,每個bit位表示一個unsigned int。讀入40億個數,並設置相應的bit位為1.然后讀取要查詢的數,查看該bit是否為1,是1則存在,否則不存在。
參考:編程珠璣-位圖數據結構