<<表示左移, 左移一位表示原來的值乘2.
比如:3 <<2(3為int型)
1)把3轉換為二進制數字0000 0000 0000 0000 0000 0000 0000 0011,
2)把該數字高位(左側)的兩個零移出。其它的數字都朝左平移2位,
3)在低位(右側)的兩個空位補零。則得到的終於結果是0000 0000 0000 0000 0000 0000 0000 1100,
轉換為十進制是12。
同理,>>表示右移. 右移一位表示除2.
位運算:
位運算符包含: 與(&)、非(~)、或(|)、異或(^)
&:當兩邊操作數的位同一時候為1時,結果為1,否則為0。如1100&1010=1000
| :當兩邊操作數的位有一邊為1時,結果為1。否則為0。如1100|1010=1110
~:0變1,1變0
^:兩邊的位不同一時候。結果為1。否則為0.如1100^1010=0110
位運算與位移動執行符的一個場景:
HashMap的功能是通過“鍵(key)”可以高速的找到“值”。以下我們分析下HashMap存數據的基本流程:
1、 當調用put(key,value)時,首先獲取key的hashcode,int hash = key.hashCode();
2、 再把hash通過一下運算得到一個int h.
hash ^= (hash >>> 20) ^ (hash >>> 12);
int h = hash ^ (hash >>> 7) ^ (hash >>> 4);
為什么要經過這種運算呢?這就是HashMap的高明之處。先看個樣例。一個十進制數32768(二進制1000 0000 0000 0000),經過上述公式運算之后的結果是35080(二進制1000 1001 0000 1000)。看出來了嗎?也許這樣還看不出什么,再舉個數字61440(二進制1111 0000 0000 0000)。運算結果是65263(二進制1111 1110 1110 1111)。如今應該非常明顯了,它的目的是讓“1”變的均勻一點。散列的本意就是要盡量均勻分布。
3、 得到h之后。把h與HashMap的承載量(HashMap的默認承載量length是16,能夠自己主動變長。在構造HashMap的時候也能夠指定一個長 度。這個承載量就是上圖所描寫敘述的數組的長度。)進行邏輯與運算,即 h & (length-1),這樣得到的結果就是一個比length小的正數。我們把這個值叫做index。事實上這個index就是索引將要插入的值在數組中的 位置。
第2步那個算法的意義就是希望能夠得出均勻的index。這是HashTable的改進,HashTable中的算法僅僅是把key的 hashcode與length相除取余。即hash % length。這樣有可能會造成index分布不均勻。
另一點須要說明,HashMap的鍵能夠為null,它的值是放在數組的第一個位置。
4、 我們用table[index]表示已經找到的元素須要存儲的位置。先推斷該位置上有沒有元素(這個元素是HashMap內部定義的一個類Entity, 基本結構它包括三個類,key,value和指向下一個Entity的next),沒有的話就創建一個Entity<K,V>對象,在 table[index]位置上插入。這樣插入結束;假設有的話,通過鏈表的遍歷方式去逐個遍歷,看看有沒有已經存在的key,有的話用新的value替 換老的value。假設沒有。則在table[index]插入該Entity,把原來在table[index]位置上的Entity賦值給新的 Entity的next。這樣插入結束。
以下解說一下原碼->反碼->補碼之間的相互關系
[-3]反=[10000011]反=11111100
原碼 反碼
負數的補碼是將其原碼除符號位之外的各位求反之后在末位再加1。
[-3]補=[10000011]補=11111101
原碼 補碼
也就是說原碼轉換成補碼是先原碼 反碼 最后+1成補碼。位運算都是補碼運算的,所以位運算后要再取反+1才得到真正的原碼。
應用舉例
(1) 推斷int型變量a是奇數還是偶數
a&1 = 0 偶數
a&1 = 1 奇數
(2) 取int型變量a的第k位 (k=0,1,2……sizeof(int))。即a>>k&1
(3) 將int型變量a的第k位清0。即a=a&~(1 < <k)
(4) 將int型變量a的第k位置1, 即a=a ¦(1 < <k)
(5) int型變量循環左移k次,即a=a < <k ¦a>>16-k (設sizeof(int)=16)
(6) int型變量a循環右移k次,即a=a>>k ¦a < <16-k (設sizeof(int)=16)
(7)整數的平均值
對於兩個整數x,y,假設用 (x+y)/2 求平均值。會產生溢出。由於 x+y 可能會大於INT_MAX,可是我們知道它們的平均值是肯定不會溢出的。我們用例如以下算法:
int average(int x, int y) //返回X,Y 的平均值
{
return (x&y)+((x^y)>>1);
}
(8)推斷一個整數是不是2的冪,對於一個數 x >= 0,推斷他是不是2的冪
boolean power2(int x)
{
return ((x&(x-1))==0)&&(x!=0)。
}
(9)不用temp交換兩個整數
void swap(int x , int y)
{
x ^= y;
y ^= x;
x ^= y;
}
(10)計算絕對值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ; //or: (x+y)^y
}
(11)取模運算轉化成位運算 (在不產生溢出的情況下)
a % (2^n) 等價於 a & (2^n - 1)
(12)乘法運算轉化成位運算 (在不產生溢出的情況下)
a * (2^n) 等價於 a < < n
(13)除法運算轉化成位運算 (在不產生溢出的情況下)
a / (2^n) 等價於 a>> n
例: 12/8 == 12>>3
(14) a % 2 等價於 a & 1
(15) if (x == a) x= b;
else x= a;
等價於 x= a ^ b ^ x;
(16) x 的 相反數 表示為 (~x+1)
實例
功能 ¦ 演示樣例 ¦ 位運算
----------------------+---------------------------+--------------------
去掉最后一位 ¦ (101101->10110) ¦ x >> 1
在最后加一個0 ¦ (101101->1011010) ¦ x < < 1
在最后加一個1 ¦ (101101->1011011) ¦ x < < 1+1
把最后一位變成1 ¦ (101100->101101) ¦ x ¦ 1
把最后一位變成0 ¦ (101101->101100) ¦ x ¦ 1-1
最后一位取反 ¦ (101101->101100) ¦ x ^ 1
把右數第k位變成1 ¦ (101001->101101,k=3) ¦ x ¦ (1 < < (k-1))
把右數第k位變成0 ¦ (101101->101001,k=3) ¦ x & ~ (1 < < (k-1))
右數第k位取反 ¦ (101001->101101,k=3) ¦ x ^ (1 < < (k-1))
取末三位 ¦ (1101101->101) ¦ x & 7
取末k位 ¦ (1101101->1101,k=5) ¦ x & ((1 < < k)-1)
取右數第k位 ¦ (1101101->1,k=4) ¦ x >> (k-1) & 1
把末k位變成1 ¦ (101001->101111,k=4) ¦ x ¦ (1 < < k-1)
末k位取反 ¦ (101001->100110,k=4) ¦ x ^ (1 < < k-1)
把右邊連續的1變成0 ¦ (100101111->100100000) ¦ x & (x+1)
把右起第一個0變成1 ¦ (100101111->100111111) ¦ x ¦ (x+1)
把右邊連續的0變成1 ¦ (11011000->11011111) ¦ x ¦ (x-1)
取右邊連續的1 ¦ (100101111->1111) ¦ (x ^ (x+1)) >> 1
去掉右起第一個1的左邊 ¦ (100101000->1000) ¦ x & (x ^ (x-1))
推斷奇數 (x&1)==1
推斷偶數 (x&1)==0
比如求從x位(高)到y位(低)間共同擁有多少個1
public static int FindChessNum(int x, int y, ushort k)
{
int re = 0;
for (int i = y; i <= x; i++)
{
re += ((k >> (i - 1)) & 1);
}
return re;
}