求Integer中二进制1的个数

尊重原创,转载请标明出处   http://blog.csdn.net/abcdef314159

在上一篇中详细介绍了Android中的Integer类,其中有一个方法bitCount(int i),他表示返回二进制中1的个数 ,我们看一下

	public static int countBit(int i) {
		i = i - ((i >>> 1) & 0x55555555);
		i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
		i = (i + (i >>> 4)) & 0x0f0f0f0f;
		i = i + (i >>> 8);
		i = i + (i >>> 16);
		return i & 0x3f;
	}

如果不明白可以看一下Integer源码详解,如果不太好理解那么就再改一下。

	public static int countBit(int i) {
		i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
		i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
		i = (i & 0x0f0f0f0f) + ((i >> 4) & 0x0f0f0f0f);
		i = (i & 0x00ff00ff) + ((i >> 8) & 0x00ff00ff);
		i = (i & 0x0000ffff) + ((i >> 16) & 0x0000ffff);
		return i & 0x3f;
	}

这个就比较通俗易懂,更好理解。那么除了bitCount方法以外还有没有其他的方法来求二进制中1的个数呢,那么这一篇就来详细介绍一下求二进制中1的个数的其他方法。

	public static int countBit(int i) {
		int sum = 0;
		while (i != 0) {
			if (i % 2 == 1) {
				sum++;
			}
			i /= 2;
		}
		return sum;
	}

这是最简单的方法,乍一看好像还很对,我们看一下
		System.out.println(countBit(33));
		System.out.println(countBit(15));
		System.out.println(countBit(0));
		System.out.println(countBit(-1));

运行结果

2
4
0
0

因为负数是通过补码的形式存在的,-1的补码是32个一,很明显最后一个是错误的。那么在修改一下

	public static int countBit(int i) {
		int sum = 0;
		while (i != 0) {
			if (i % 2 == 1) {
				sum++;
			}
			i = (i >>> 1);
		}
		return sum;
	}

既然负数是通过补码形式存在的,那么通过移位是不是就没问题了,再看一下运行结果

2
4
0
31

可是这样发现也不对,明明是32个1的,这里为什么是31个,其实这里犯了一个大忌,因为判断一个数是否是奇偶数不能用等号,要用不等号,为什么这么说,因为负奇数对2求余是得-1的,这里再改一下,用不等号

	public static int countBit(int i) {
		int sum = 0;
		while (i != 0) {
			if (i % 2 != 0) {
				sum++;
			}
			i = (i >>> 1);
		}
		return sum;
	}
再看一下运行结果

2
4
0
32

所以这种写法才是正确的。当然还可以这样写

	public static int countBit(int i) {
		int sum = 0;
		while (i != 0) {
			if ((i&1)!= 0) {
				sum++;
			}
			i = (i >>> 1);
		}
		return sum;
	}

运行结果也是正确的,当然还可以这样写

	public static int countBit(int i) {
		int sum = 0;
		while (i != 0) {
			sum+=i&1;
			i = (i >>> 1);
		}
		return sum;
	}

下面这样写也对

	public static int countBit(int i) {
		int sum = 0;
		while (i != 0) {
			i &= i - 1;
			sum++;
		}
		return sum;
	}
这样可能不太好理解,如果你随便写几个就会明白,他会把最后的1一个个消除,直到变为0为止。还有下面这种方式
	public static int countBit(int i) {
		int count = 0;
		for (int j = 0; j < 32; j++) {
			if ((i & (1 << j)) >>> j == 1)
				count++;
		}
		return count;
	}

原理很简单就是通过1与各位上的数字与运算,如果为1就count++,当然还可以改为下面这种方式

	public static int countBit(int i) {
		int count = 0;
		for (int j = 0; j < 32; j++) {
			if ((i & (1 << j)) != 0)
				count++;
		}
		return count;
	}
判断每个位置上是否有1,还可以下面修改
	public static int countBit(int i) {
		int count = 0;
		for (int j = 0; j < 32; j++) {
			if ((i & 1) == 1)
				count++;
			i >>= 1;
		}
		return count;
	}

这个使用i>>=1,严格来说应该使用i>>>=1更合适,但为什么前面一种方式也不会差错是因为for循环中就循环了32次,即使是负数也没关系,结果一样正确,下面再看一下其他方式。

	public static int countBit(int i) {
		//table是0到15转化为二进制时1的个数
		int table[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
		int count = 0;
		while (i != 0) {//通过每4位计算一次,求出包含1的个数
			count += table[i & 0xf];
			i >>>= 4;
		}
		return count;
	}
注释很明显就不在详述,上面只是4个一组求的,还可以八个一组,当然数组元素也很多,这里就不在列出。通过发现,只要认真挖掘总还能找到,那就继续,在上一篇讲到bitCount方法的时候,第一步是每两位存储1的个数,那么能不能每3位存储呢,当然可以,看代码
	public static int countBit(int i) {
		// 每3个计算存储
		int tmp = (i - ((i >>> 1) & 033333333333) - ((i >>> 2) & 011111111111));
		// 因为Integer是32位,这里最前面是2个一个组合,后面的10个是每3个组合,正好是32位,总共11组,后面的每2组相加,
		// 最前面的一组不动,所以下面的与运算最前面的3把它保留了(030707070707每3位一组,这里是8进制)
		tmp = ((tmp + (tmp >>> 3)) & 030707070707);
		// 每6位数相加,即2组
		tmp = ((tmp + (tmp >>> 6)) & 07700770077);
		tmp = ((tmp + (tmp >>> 12)) & 037700007777);
		// 这里为什么要与63进行与运算,按说如果与077777777进行与运算也没错,8进制的8个7相当于24个1
		//但因为Integer最多也就32个1,所以取后几位也就足够了
		return ((tmp + (tmp >>> 24))) & 63;
	}
这个方法也是可以的,只不过在最开始的时候他是每3个存放,原理很简单,主要把上面的8进制换成二进制就一目了然。那么既然能每3个存储,每四个是不是也可,当然可以,看代码
	public static int countBit(int i) {
		int tmp = i - ((i >>> 1) & 0x77777777) - ((i >>> 2) & 0x33333333)
				- ((i >>> 3) & 0x11111111);
		tmp = ((tmp + (tmp >>> 4)) & 0x0f0f0f0f);
		tmp = ((tmp + (tmp >>> 8)) & 0x00ff00ff);
		return ((tmp + (tmp >>> 16)) & 0x0000ffff) % 63;
	}
这个比上面一个更简单,因为4个一组正好分成8组,不会像上面3个一组出现分不均的情况。当然还有其他方法也可以求,这里就不在介绍,也可以参考一下 Hamming weight


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据结构和算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值