反轉乙個位元組和判斷32位整數二進位制中1的個數等演算法

2021-04-23 10:07:24 字數 2481 閱讀 2630

unsigned char reverse8( unsigned char c )

unsigned long func(unsigned long x)

x&=x-1;

本帖**http://blog.csdn.net/todototry/archive/2007/04/23/1575900.aspx

但是更加詳細的說明如下:

這兩個函式極很是巧妙,作了平行計算。

先看問題1: 反轉乙個位元組。

它的演算法是這樣的: 首先是2位2位為一組,交換前一半和後一半。再4位4位為一組,交換前一半和後一半。再8位為一組,交換前一半和後一半

。可能還有點說不清楚。我舉個例子。

將1 2 3 4 5 6 7 8 反轉。

(1)2個2個為一組,交換前一半和後一半, 變成。

2 1 4 3 6 5 8 7

(2)4個4個為一組,交換前一半和後一半, 變成

4 3 2 1 8 7 6 5

(3)再8個為一組,交換前一半和後一半, 變成

8 7 6 5 4 3 2 1

反轉成功。

這樣的演算法本來很是簡單,很容易用數學歸納法證明其正確。這函式, 巧妙就巧妙在作了平行計算,分組,它一次就計算完了。

先看第乙個語句。c = ( c & 0x55) << 1 | ( c & 0xaa ) >> 1;

0x55其實就是01010101, 0xaa就是10101010

假設 c=abcdefgh

c & 0x55 = 0b0d0f0h,     c & 0xaa = a0c0e0g0

跟著,前者左移一位, b0d0f0h0, 後者右移一位, 0a0c0e0g, 再乙個|運算,就兩位兩位交換了位置。

想象一下,你有乙個長紙條,分成一格一格,每格寫乙個字,假如你將紙條每隔一格剪乙個小洞,滑一格,覆蓋在原來的紙條上,你就會看到兩個兩個字交換了位置。

(注: |運算可以換成+運算,想一想為什麼)

第二個語句。 c = ( c & 0x33 ) << 2 | ( c & 0xcc ) >> 2;

0x33 = 00110011, 0xcc=11001100。

第三個語句。c = ( c & 0x0f ) << 4 | ( c & 0xf0 ) >> 4;

0x0f = 00001111, 0xf0=11110000.

這兩個語句的作用也是 分組,將一半位變成0,移位滑動,跟著再組合,就分組交換了位置。

不防想象兩個小紙條剪洞疊加。

這方法應該可以推廣。

理解了問題1,也就很容易理解問題2了.

問題2: 判斷32位整數二進位制中1的個數。

和問題1一樣,也是採用了分組平行計算。

基本方法是: 2位2位為一組,相加,看看有幾個1。再4位4位為一組,相加,看看有幾個1......

還是說的不太明白。接著分析。

為了簡單說明,先看看8位的情形。相應地,函式裡面的語句變成。

x = (x & 0x55) + ((x >> 1) & 0x55);    (1)

x = (x & 0x33) + ((x >> 2) & 0x33);    (2)

x = (x & 0x0f) + ((x >> 4) & 0x0f);    (3)

return x;

假設x=abcdefgh. 0x55=01010101

x & 0x55 = 0b0d0f0h.   (x>>1) & 0x55 = 0a0c0e0g。相加。就可以知道2位2位一組1的個數。

比如x=11111111

x= (x & 0x55) + ((x >> 1) & 0x55); 之後x=10101010。你2位2位地看,10=2, 就是2 2 2 2, 就是說各組都是2個1。

比如x=00101001

x= (x & 0x55) + ((x >> 1) & 0x55); 之後x=00010101。你2位2位地看,就是0 1 1 1, 前1組只有0個1,後面的組都是1個1。

好啦。再來看。0x33=00110011。

x=abcdefgh.

x=(x & 0x33)+((x >> 2)&0x33); 相當於, 00ab00ef + 00cd00gh。

因為語句(1)之後。ab指示了頭兩位有多少個1,cd指示了下兩位有多少個1。相加00ab+00cd就指示前4位有多少個1。這樣就是4位4位為一組。注意這樣的分組,組與組之間永遠都不會產生進製的。正因為不會產生進製,才可以分開來看。

好啦。下面的過程都是一樣的,不再多說。

8位,16位,32位都一樣。

反過來推導,基本思想還是2分法。

給你乙個x,設f(x,n)表示x中2進製位1的個數,則

f(x)=f(x & 0x0000fffful) + f((x >> 16) & 0x0000fffful)

乙個32位的化成兩個16位的,16位的再化成兩個8位的,而且可以就在x上進行計算,保持數量不變,一直1位的x本身32位。

再從前面往後走

unsigned long func(unsigned long x)

經典 反轉乙個位元組

這道題很古老了,可別將它和大端轉小端混淆了,所謂大端和小端指的是位元組序,而這裡反轉乙個位元組說的是位序,演算法更是不勝列舉,說實話都能達到目的,剩餘的就是看看誰的效率更高了,基本上這是乙個最難的問題,高手不是能寫出最美麗的程式而是能寫出既美麗同時效率又是最高的程式,如果乙個人寫的程式很美麗,很直觀...

筆試題 反轉乙個位元組

這道題很古老了,可別將它和大端轉小端混淆了,所謂大端和小端指的是位元組序,而這裡反轉乙個位元組說的是位序,演算法更是不勝列舉,說實話都能達到目的,剩餘的就是看看誰的效率更高了,基本上這是乙個最難的問題,高手不是能寫出最美麗的程式而是能寫出既美麗同時效率又是最高的程式,如果乙個人寫的程式很美麗,很直觀...

怎麼把位域合成乙個位元組 位域 bit field

一 位域 有些資訊在儲存時,並不需要占用乙個完整的位元組,而只需佔幾個或乙個二進位制位。例如在存放乙個開關量時,只有0和1 兩種狀態,用一位二進位即可。為了節省儲存空間,並使處理簡便,語言又提供了一種資料結構,稱為 位域 或 位段 所謂 位域 是把乙個位元組中的二進位劃分為幾 個不同的區域,並說明每...