1. 程式人生 > >操作二進位制的(記錄)

操作二進位制的(記錄)

問題1

給你一個值(char,int....),當然他們在記憶體中都是二進位制存在的,怎麼反轉它們的值呢?

int型

比如  (0x00006CBA)  0000 0000  0000 0000   0110 1100  1011 1010 (27834) 

二進位制和十六進位制不熟,直接計算器(囧)

這個數比較小,只是舉個例子, 我們直接用眼睛瞅可以得出:

0101 1101  0011 0110  0000 0000  0000 0000 => 1563820032 (0x5D360000)

顯然,容易瞅錯,要是別人問你,或者你面試,面試官難為你,你這不就笑話了麼....還得隨帶個計算器...

扯淡哈.....

這就涉及到一個演算法,叫做 分治法 

我的粗糙理解就是,取最小的問題解決,然後擴大(一般是倍數),直到解決問題,在實現上遞迴式比較常用的。

扯遠...

用到這個題上就是,你想倒轉,那我從最小組的倒轉,自己和自己換沒意義,那我就相鄰的兩個換。各兩個互換後,他倆成為一組在和相鄰的別的組互換....當只有兩組的時候,他倆一換,全部倒騰完了...

參見一個小夥伴的講解:

當然 出現了這麼幾個神奇的二進位制數

0x5555555555555555(long) (0101010101010101010101010101010101010101010101010101010101010101)

太長了,一下用x86int來解說:

0x55555555 =     (01010101010101010101010101010101) (1431655765)如果你的偵錯程式好你可以看到整數。

0xAAAAAAAA = (10101010101010101010101010101010)  (2863311530)

0x33333333  =     (00110011001100110011001100110011) 

0xCCCCCCCC =(11001100110011001100110011001100)

0x0f0f0f0f

0xf0f0f0f0

0x00ff00ff

0xff00ff00

0x0000ffff

0xffff0000   以下自行二進位制............

看著16進位制好怪,無非就是二進位制各位不同,就是每一位和其餘都不相同意思,由於是二進位制,所以一定是10,擴大組就變成

1100  1111000 .... 依次

用幹啥呢,用來反轉的

num = ((num >> 1) & 0x55555555) | ((num << 1) & 0xAAAAAAAA);

當引數 v >> 右移1,與(0x05) 0101 相與(留奇),得到 把偶數位放到奇數上,把偶數上位變零

當引數 v << 左移1,與(0x0A) 1010 相與(留偶),得到 把奇數位放到偶數上,把奇數上位變零

然後相加(+)或者相或(|),就達到了兩位兩位反轉的目的。

然後利用遞迴原理,擴大分組, << 右移2   >>左移 2  , 與 0011(留奇)  1100(留偶)

<< 右移4   >>左移 4  , 與 0001111(留奇)  11110000(留偶)

至於多大取決於你的位元組長度,如果是int,那麼 16 就可以了 32 位麼,最後一次到移位16 就完成目標啦,

當然你要是long或者更大,那就看你自己平臺了,long 應為 64 位,八個位元組,那就在>>32吧。

所以有一下演算法:類C實現(int)

        private static long Number5(uint num)
        {
            num = ((num >> 1) & 0x55555555) | ((num << 1) & 0xaaaaaaaa);
            num = ((num >> 2) & 0x33333333) | ((num << 2) & 0xcccccccc);
            num = ((num >> 4) & 0x0f0f0f0f) | ((num << 4) & 0xf0f0f0f0);
            num = ((num >> 8) & 0x00ff00ff) | ((num << 8) & 0xff00ff00);
            num = ((num >> 16) & 0x0000ffff) | ((num << 16) & 0xffff0000);
            return num;
        }

神奇有沒有,對於不熟悉二進位制的上層程式設計師,不研究一會真不知道他們整的是啥....

問題2

查出一個int型別數二進位制有多少個1。

我個菜鳥,絞盡腦汁:

 private static int Number(int figure)
 {
      var cout = 0;
      var temp = figure;
      while (temp != 0)
      {
         var c = (temp & 1);
         if (c == 1) cout++;
         temp = temp >> 1;
       }
       return cout;
 }

然後看見更好的演算法...

 private static  int Number(int figture)
        {
            int num = 0;
            while (figture > 0)
            {
                figture &= (figture - 1);
                num++;
            }
            return num;
        }

然後分治法又出來了...

        private static int Number2(int a)
        {
            a = (a & 0x55555555) + ((a >> 1) & 0x55555555);
            a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
            a = (a & 0x0f0f0f0f) + ((a >> 4) & 0x0f0f0f0f);
            a = (a & 0x00ff00ff) + ((a >> 8) & 0x00ff00ff);
            a = (a & 0x0000ffff) + ((a >> 16) & 0x0000ffff);
            return a;
        }

看看小夥伴的文章:

然後這個我也看懂了:

        private static int Number4(long x)
        {
            x -= (x >> 1) & 0x5555555555555555;           
            x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
            x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
            x += x >>  8;
            x += x >> 16;
            x += x >> 32;
            return x &0xff;
        }

然後看不懂了...

int static  Number5(long x) {
    x -= (x >> 1) & m1;             
    x = (x & m2) + ((x >> 2) & m2); 
    x = (x + (x >> 4)) & m4;        
    return (x * h01)>>56;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... 
}

行吧,程式猿的世界,總是有看不懂程式碼,先記下來,沒事再燒燒腦....