leetcode 190 Reverse Bits

Reverse bits of a given 32 bits unsigned integer.markdown

For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as 00111001011110000010100101000000).網絡

Follow up:
If this function is called many times, how would you optimize it?
ui

解決方案:
Basically, this code is just keeping pop the last bit from n and push it to the end of the return result.
this

Do
•Get last bit from n
•Push the bit to the end of the result
•Pop out the last bit of n


url

Until n is 0
•Push remaining 0s to the n by 「ret << nShift」
spa

•Return the result 「ret」.net

uint32_t ret = 0;

    int nShift = 32;
    while (n && nShift--)
    {
        // shift ret to left by one and move a room for the new push
        ret = (ret << 1);
        // Push the last bit of the n to ret
        if (n%2)
            ret |= 0x1;
        // pop the last element out
        n = (n>>1);
    }

    return ret << nShift;

位操做詳解code

參考:http://www.crazycpp.com/?p=82遊戲

咱們先來看看位運算操做符:& (按位與)、| (按位或)、^ (按位異或)、~ (按位取反)、>> (按位右移)、<< (按位左移)。element

一、&(按位與) 從概念上來說,就是將參與運算的兩個份量對應的每一位來作邏輯與運算,若二者都爲真(等於1),則結果才爲真(等於1)。不然都爲假(等於0)。
即:1 & 1 = 1 、1&0 = 0 、0&1 = 一、0&0 = 0
這裏咱們先來看看那一個8位二進制的例子:
7&8 = 0000 0111 & 0000 1000 = 0000 0000 = 0
7&6 = 0000 0111 & 0000 0110 = 0000 0110 = 6



二、| (按位或) 即把參與運算的每一個份量對應的每一位來作邏輯或運算,即二者都爲假(爲0)時,才爲假(爲0),不然皆爲真。
即:0|0 = 0、1|0 = 一、0|1 = 一、1|1 = 1
來看看8位二進制的例子:
7|8 = 0000 0111 | 0000 1000 = 0000 1111 = 15
7|6 = 0000 0111 | 0000 0110 = 0000 0111 = 7



三、^(按位異或) 即把參與運算的每一個份量對應的每一位來作異或運算,即二者相同爲假,不一樣爲真。
即:0|0 = 0、 1|0 = 一、0|1 = 一、 1|1 = 0
看下面的例子:
7^8 = 0000 0111 ^ 0000 1000 = 0000 0111 = 7
7^6 = 0000 0111 ^ 0000 0100 = 0000 0011 = 3



四、~(按位取反) 即把二進制位的每一位進行取反運算,簡而言之就是1變成0,0變成1。
直接看例子:
~7 = ~0000 0111 = 1111 1000 = 248

5 >>(按位右移)把二進制位總體向右移動。
7>>1 = 0000 0111 >> 1 = 0000 0011 = 3
7>>2 = 0000 0111 >> 2 = 0000 0001 = 1
這裏右移等於除了2的N次方,N爲右移的位數。


6 <<(按位左移)這裏就不詳細說了,和右移相反。

位操做應用

好了,下面講講實際應用吧。
1、一種顏色的表示方式—- 經過DWORD來表示顏色
定義:typedef unsigned long DWORD;
即爲一個無符號32位(32機器)長整數,有四個字節,咱們從左到右叫他1,2,3,4字節,每個字節的範圍是0~255。第一個字節表示alpha值,即透明度。若是是255,表示不透明,0表示徹底透明(


看不到),其餘分別是R,G,B值。
可經過下列方法得到每一個字節的值:
int A = (int)((DWORD & 0xFF000000) >> 24);
int R = (int)((DWORD & 0x00FF0000) >> 16);
int G = (int)((DWORD & 0x0000FF00) >> 8);
int B = (int)(DWORD & 0x000000FF);




DWORD dwColor = (A<<24)+(R<<16)+(G<<8)+B;
有了前面的基礎,我相信你們對上面的換算方法,一看就明白吧。若是對16進制不敏感的童鞋,能夠用計算機把十六進制換算成二進制,更容易理解。

2、狀態系統中的使用

在遊戲開發中,咱們一般用一個32位(假設這裏用32位)的整數來存儲角色的狀態(這樣作主要是爲了節約存儲空間,同時也減少網絡同步消息包的size)。所謂的狀態,就是你們熟悉的Buff或者DeBuff。
enum ROLE_STATUS
{
STATUS_NORMAL = 0, // 正常
STATUS_DIE = 1, // 死亡狀態
STATUS_GOD , // 無敵
STATUS_DISAPPEARING , // 消失中狀態
STATUS_DEF_ADJUST , // 物理防護提高/下降
STATUS_MDEF_ADJUST , // 魔法防護提高/下降
STATUS_ATK_CRI_ADJUST , // 同時提高物理攻擊和爆擊率
STATUS_MAXHP_ADJUST , // HP上限調整
STATUS_MAXMP_ADJUST , // MP上限提高/下降
//……
這裏最多隻能寫32個,由於咱們假設是用32位數據來存儲狀態。
};













狀態數據定義好了,如今來看看怎麼使用他們。
首先, 角色上線,我要給他一個保護狀態,應該這樣操做。
DWORD dwRoleStatus = STATUS_GOD;
同時,角色使用了一個物品,這個物品的效果時,HP和MP上限增長一段時間。所以要附加調整玩家的HP和MP上限的狀態,應該這樣。
DWORD dwRoleStatus |= (STATUS_MAXHP_ADJUST+STATUS_MAXMP_ADJUST);
這裏是|=而不是=操做,由於不能清掉以前附加的無敵保護狀態。因此用或運算。
該角色受到其餘玩家或者怪物的攻擊,咱們要判斷被攻擊的這個角色的受保護狀態狀態還在不在。執行以下邏輯
if( dwRoleStatus & STATUS_GOD ) // 判斷位是否爲1
{
// 受保護狀態,不能被攻擊
}









接下來,角色無敵保護時間過時了,咱們要清除無敵狀態,執行以下操做
dwRoleStatus &= ~STATUS_GOD;
這裏用到了取反的計算。~STATUS_GOD的結果是第二位爲0外,其餘都爲1。而後和dwRoleStatus作按位與計算。
STATUS_GOD 等於 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010;
~STATUS_GOD 等於 1111 1111 1111 1111 1111 1111 1111 1111 1111 1101;
所以和dwRoleStatus相與以後,dwRoleStatus除了第二位之外的位,都保留下來了。第二位不論是什麼值,都會被設置爲0,這樣子就把STATUS_GOD這個狀態清除掉了。同理咱們要清除多個狀態的時候,先把要清楚的狀態或運算到一塊兒。再取反,而後和dwRoleStatus按位與。起到同時清除多個狀態。




而後講講異或,它有一個性質是,兩次異或,能還原回來

例如 a=7,b=6;

a = a^b^b

咱們來看看那二進制的操做

a = 0111

b = 0110

c = a^b = 0001

a = c^b = 0111

寫到這裏,想到一道經典的C++筆試題,即不須要第3個變量,交換兩個變量的值。

a = a^b = 0001

b = b^a = 0111

a = a^b = 0110

相關文章
相關標籤/搜索