求二进制数中1的个数 | hamming_weight

题目:对于一个字节的无符号整型变量,求其二进制表示中1的个数。


解法1:位操作法

(这里又细分成2中方法,详见代码)

<?php 
$num = 6;
$count = 0;
while($num) {
	$num = $num & ($num - 1); //时间复杂度:O(m) ,即无符号整形中(二进制)1的个数)
	$count++;
}
/* another method:
 while($num) {
 	if(($num & 1) != 0) {   // 时间复杂度:O(log n) ,右移位运算就是除以2)
 		$count ++;
 	}
 	$num = $num>>1;
 } 
 */
var_dump($num);
var_dump($count);
?>


解法2:hamming_weight:对任何32位的无符号整形,都只需要5次移位运算,时间复杂度为常数,所以为O(1)

参考:Hamming weight高效统计整数二进制表示中1的个数(http://www.buguw.com)

参考:http://en.wikipedia.org/wiki/Hamming_weight


原理:这里运用了分治的思想,先计算每对相邻的2位中有几个1,再计算每相邻的4位中有几个1,下来8位,16位,32位,因为2^5=32,所以对于32位的机器,5条位运算语句就够了。

我画的一张图:

求二进制数中1的个数 | hamming_weight_第1张图片


wiki上的图表:

Expression Binary Decimal Comment
A 0110110010111010   The original number
B = A & 01 01 01 01 01 01 01 01 01 00 01 00 00 01 00 00 1,0,1,0,0,1,0,0 every other bit from A
C = (A >> 1) & 01 01 01 01 01 01 01 01 00 01 01 00 01 01 01 01 0,1,1,0,1,1,1,1 the remaining bits from A
D = B + C 01 01 10 00 01 10 01 01 1,1,2,0,1,2,1,1 list giving # of 1s in each 2-bit piece of A
E = D & 0011 0011 0011 0011 0001 0000 0010 0001 1,0,2,1 every other count from D
F = (D >> 2) & 0011 0011 0011 0011 0001 0010 0001 0001 1,2,1,1 the remaining counts from D
G = E + F 0010 0010 0011 0010 2,2,3,2 list giving # of 1s in each 4-bit piece of A
H = G & 00001111 00001111 00000010 00000010 2,2 every other count from G
I = (G >> 4) & 00001111 00001111 00000010 00000011 2,3 the remaining counts from G
J = H + I 00000100 00000101 4,5 list giving # of 1s in each 8-bit piece of A
K = J & 0000000011111111 0000000000000101 5 every other count from J
L = (J >> 8) & 0000000011111111 0000000000000100 4 the remaining counts from J
M = K + L 0000000000001001 9 the final answer

<?php
/**
 * @author:wusuopubupt
 * @date:2013-10-24
 * @url :http://en.wikipedia.org/wiki/Hamming_weight
 * 
 * @return:Hamming Weight of a decimal number
 */
define('M1', hexdec("55555555"));  //hex:0x55555555,binary: 0101...
define('M2', hexdec("33333333"));  //binary: 0011..
define('M4', hexdec("0f0f0f0f"));  //binary: 00001111.....
define('M8', hexdec("00ff00ff"));  //binary: 0000000011111111 ...
define('M16',hexdec("0000ffff"));  //binary: 00000000000000001111111111111111

//echo hexdec("f"); //15
//echo base_convert("f", 16, 2); //1111

function popcount($n) {
	$n = ($n & M1 ) + (($n >>  1) & M1 ); //put count of each  2 bits into those  2 bits
	$n = ($n & M2 ) + (($n >>  2) & M2 ); //put count of each  4 bits into those  4 bits
	$n = ($n & M4 ) + (($n >>  4) & M4 ); //put count of each  8 bits into those  8 bits
	$n = ($n & M8 ) + (($n >>  8) & M8 ); //put count of each 16 bits into those 16 bits
	$n = ($n & M16) + (($n >> 16) & M16); //put count of each 32 bits into those 32 bits
	
	return $n;
}

$count = popcount(255);
var_dump($count);


你可能感兴趣的:(求二进制数中1的个数 | hamming_weight)