學習筆記 詳解一種高效位反轉演算法
詳解一種高效位反轉演算法
位反轉
這裡的位反轉(Bit Reversal),指的是一個數的所有bit位依照中點對換位置,例如0b0101 0111 => 0b1110 1010。也可以叫二進位制逆序,按位逆序,位翻轉等等。
演算法原理
高效位反轉演算法原理:演算法運用了分治法(divide and conquer),以兩個bit位一組,對調相鄰的bit位;然後再以4個bit位為一組,分成左邊兩個bit位一段和右邊兩個bit位一段,然後這兩段相互對調;然後再以8個bit位為一組,以此類推,最後完成位反轉。
32位數的高效位反轉演算法實現
下面舉例一個32位數的高效位反轉演算法程式碼:
unsigned int reverse(unsigned int x)
{
x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
return((x >> 16) | (x << 16));
}
下面進行逐行程式碼分析:
首先,我們要進行位反轉的是一個32位數,如下圖所示
分析第一行程式碼:
x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
-
0xaaaaaaaa
0xaaaaaaaa 是從第0位開始,所有奇數位為1
0xaaaaaaaa = 0b10101010101010101010101010101010
-
x & 0xaaaaaaaa
x & 0xaaaaaaaa的結果如下圖所示:
(x & 0xaaaaaaaa) >> 1
右移一位後結果如下圖所示:
-
0x55555555
0x55555555是從第0位開始,所有偶數位為1
0x55555555 = 0b01010101010101010101010101010101
-
x & 0x55555555
x & 0x55555555的結果如下圖所示:
-
(x & 0x55555555) << 1
左移一位的結果如下圖所示:
x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
然後兩個數或運算,結果如下圖所示:
第一行程式碼運算完成。
總結,x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
這行的程式碼就是以兩個bit位一組,對調相鄰的bit位。
圖解就是將下圖
轉換成
分析第二行程式碼:
x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
目前x的數值為:
-
0xcccccccc
0xcccccccc是從第0位開始,0和1每隔兩位交替出現0
xcccccccc = 0b11001100110011001100110011001100 -
x & 0xcccccccc
x & 0xcccccccc的結果如下圖所示:
-
(x & 0xcccccccc) >> 2
右移兩位後結果如下圖所示:
-
0x33333333
0x33333333是從第0位開始,1和0每隔兩位交替出現
0x33333333 = 0b00110011001100110011001100110011 -
x & 0x33333333
x & 0x33333333的結果如下圖所示:
(x & 0x33333333) << 2
左移兩位後結果如下圖所示:
x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
然後兩個數或運算,結果如下圖所示:
第二行程式碼運算完成。
總結,x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
這行的程式碼就是以4個bit位為一組,分成左邊兩個bit位一段和右邊兩個bit位一段,然後這兩段相互對調。
圖解就是將下圖
轉換成
分析第三行程式碼:
x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
目前x的數值為:
-
0xf0f0f0f0
0xf0f0f0f0是從第0位開始,0和1每隔四位交替出現
0xf0f0f0f0= 0b11110000111100001111000011110000 -
x & 0xf0f0f0f0
x & 0xf0f0f0f0的結果如下圖所示:
-
(x & 0xf0f0f0f0) >> 4
右移四位後結果如下圖所示:
-
0x0f0f0f0f
0x0f0f0f0f是從第0位開始,1和0每隔四位交替出現
0x0f0f0f0f= 0b00001111000011110000111100001111
-
x & 0x0f0f0f0f
x & 0x0f0f0f0f的結果如下圖所示:
-
(x & 0x0f0f0f0f) << 4
左移四位後結果如下圖所示:
-
x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
然後兩個數或運算,結果如下圖所示:
第三行程式碼運算完成。
總結,x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
這行的程式碼就是以8個bit位為一組,分成左邊四個bit位一段和右邊四個bit位一段,然後這兩段相互對調。
圖解就是將下圖
轉換成
分析第四行程式碼:
x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
目前x的數值為:
-
0xff00ff00
0xff00ff00是從第0位開始,0和1每隔八位交替出現
0xff00ff00= 0b11111111000000001111111100000000
-
x & 0xff00ff00
x & 0xff00ff00的結果如下圖所示:
-
(x & 0xff00ff00) >> 8
右移八位後結果如下圖所示:
-
0x00ff00ff
0x00ff00ff是從第0位開始,1和0每隔八位交替出現
0x00ff00ff= 0b00000000111111110000000011111111
-
x & 0x00ff00ff
x & 0x00ff00ff的結果如下圖所示:
-
(x & 0x00ff00ff) << 8
左移八位後結果如下圖所示:
-
x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
然後兩個數或運算,結果如下圖所示:
第四行程式碼運算完成。
總結,x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
這行的程式碼就是以16個bit位為一組,分成左邊八個bit位一段和右邊八個bit位一段,然後這兩段相互對調。
圖解就是將下圖
轉換成
分析最後一行程式碼:
((x >> 16) | (x << 16))
目前x的數值為:
高16bit與低16bit進行交換,結果如下圖:
完成整個位反轉演算法。
8位數的高效位反轉演算法實現
如果要對8位數進行位反轉,原理相同,程式碼如下:
unsigned char reverse(unsigned char x)
{
x = (((x & 0xaa) >> 1) | ((x & 0x55) << 1));
x = (((x & 0xcc) >> 2) | ((x & 0x33) << 2));
return ((x >> 4) | (x << 4));
}
即可實現對8位數的高效位反轉。
[參考資料]
[Hacker’s Delight] 作者: Henry S. Warren Jr.
The Aggregate Magic Algorithms
相關文章
- MIT 6.824 學習筆記(一)--- RPC 詳解MIT筆記RPC
- TensorFlow常量、變數和佔位符詳解(學習筆記)變數筆記
- Go學習筆記-GMP詳解Go筆記
- Spring---IoC(控制反轉)原理學習筆記【全】Spring筆記
- git reset 命令詳解(一)—— Git 學習筆記 07Git筆記
- 《SQL 反模式》 學習筆記SQL模式筆記
- repuest轉發學習筆記一筆記
- JVM學習筆記(3)---OutOfMemory詳解JVM筆記
- Nginx變數詳解(學習筆記十九)Nginx變數筆記
- mysql學習筆記-底層原理詳解MySql筆記
- 數位DP 學習筆記筆記
- 堆溢位學習筆記筆記
- 學習筆記:數位dp筆記
- 【學習筆記】數位DP筆記
- Flutter 高效自學筆記(一)Flutter筆記
- 演算法學習筆記演算法筆記
- git checkout 命令詳解—— Git 學習筆記 16Git筆記
- JavaWeb學習筆記_Day03_JavaScript詳解Web筆記JavaScript
- VC++深入詳解--之複習筆記(一)C++筆記
- 機器學習演算法學習筆記機器學習演算法筆記
- Floyd演算法學習筆記演算法筆記
- LMF演算法學習筆記演算法筆記
- 匈牙利演算法學習筆記演算法筆記
- Tarjan 演算法學習筆記演算法筆記
- git cherry-pick 詳解 —— Git 學習筆記 18Git筆記
- git reset 命令詳解(二)—— Git 學習筆記 08Git筆記
- 學習筆記(一)筆記
- mysql修改表欄位學習筆記MySql筆記
- 高效能運算學習筆記(1)筆記
- [高效能MYSQL學習筆記]事務MySql筆記
- 演算法學習筆記:Kosaraju演算法演算法筆記
- kernel_mktime() 詳解 —— Linux-0.11 學習筆記(四)Linux筆記
- 莫隊演算法學習筆記演算法筆記
- 資料結構和演算法-學習筆記(一)資料結構演算法筆記
- kitten 學習教程(一) 學習筆記筆記
- Angular 學習筆記(一)Angular筆記
- React 學習筆記【一】React筆記
- vue學習筆記一Vue筆記