二进制整数中的“1”

这里主要通过一些位运算的技巧来找出一个整数的二进制表示中1的个数或其中某些特殊的1的位置。

1 的个数

求二进制表示中1的个数存在时间复杂度为O(n)(n为1的个数)的算法。 其要点是 若整数 x 不为0, 表达式(指C语言表达式) x&(x-1) 的运算结果是将 x 的二进制表示中最右侧的1消除后的值, 若x为0, 表达式的值为0。 这样, 若 x 不为0, 我们就可以通过表达式  x = x&(x-1) 反复消除 x 最右侧的1直到x为0, 消除的次数即为所求1的个数。

C语言代码(输入为32位无符号整型)

1 int number_of_ones(uint32_t x) {
2     int result = 0;
3     while (x) {
4         x = x & (x - 1);
5         result++;
6     }
7     return result;
8 }

最右侧1的位置

最右侧1的位置通过表达式 x ^ (x & (x-1))计算, 如, x: 0x12345678, x ^ (x & (x-1)) : 0x00000008

1 uint32_t right_most_one(uint32_t x) {
2     return x ^ (x & (x - 1));
3 }

最左侧1的位置

求最左侧1的位置相对比较复杂, 下面是一种比较直接的算法。

1 uint32_t left_most_one(uint32_t x) {
2     uint32_t test = x & (x - 1);
3     while (test) {
4         x = test;
5         test = x & (x - 1);
6     }
7     return x;
8 }

在Java ArrayDeque 的 allocateElements 源码中看到一种比较有意思的算法, 它用来计算大于一个数的2的整数次幂。 我们可以对所求2的次幂按位右移一位来求最左侧1的位置。

下面给出源代码    ps: 自行思考一下算法的原理 :)

 1 uint32_t left_most_one2(uint32_t x) {
 2     uint32_t tmp = x;
 3     tmp |= (tmp >> 1);
 4     tmp |= (tmp >> 2);
 5     tmp |= (tmp >> 4);
 6     tmp |= (tmp >> 8);
 7     tmp |= (tmp >> 16);
 8     tmp++;
 9     return tmp ? (tmp >> 1) : (0x80000000);
10 }

参考

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayDeque.java

时间: 2024-12-08 23:43:15

二进制整数中的“1”的相关文章

判断给定十进制整数的二进制形式中含有几个1

两种判断一个给定整数的二进制形式中含有几个1的简单方法: 主要思想是通过按位与(&)运算和位移运算(<< >>)实现 1 unsigned int_number( int n) 2 { 3 if (n < 0) 4 return; 5 unsigned count = 0; 6 while (n != 0) 7 { 8 if ((n & 1) != 0) 9 ++count; 10 n >>= 1; 11 } 12 return count; 13

【C语言】输入一个整数,输出该数二进制表示中1的个数(三种方法)

输入一个整数,输出该数二进制表示中1的个数.如输入32,输出1. 代码实现: 方法1:与运算 #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; int FindOneNumber(unsigned int num) {     int numberofOne = 0;     while (num)     {         num = num & (num - 1);         

c语言:输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n

输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n? 解:第一步求这两个数的异或运算,将异或运算结果存起来:第二步统计这个运算结果当中1的位数 程序: #include<stdio.h> int count(int m,int n) { int t,count=0; t = m^n; while (t) { count++; t=t&(t-1); } return count; } int main() { int num1,num2,ret=0; printf(&qu

交换一个整数二进制表示中的奇数位和偶数位

题目 原文: 写程序交换一个整数二进制表示中的奇数位和偶数位,用尽可能少的代码实现. (比如,第0位和第1位交换,第2位和第3位交换…) 解答 这道题目比较简单.分别将这个整数的奇数位和偶数位提取出来,然后移位取或即可. 代码如下: int swap_bits(int x){ return ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555); } 当然也可以采用更自然的方式来写这段代码: int swap_bits1(

22、输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 思路: n &(n-1)把n的最右边的1去掉,用count++计算1的个数  eg: 101 & 100 = 100   1 class Solution { 2 public: 3 int NumberOf1(int n) { 4 int count = 0; 5             while(n!=0){ 6                 count++; 7                 n = n&

笔试算法题(14):整数二进制表示中的1 &amp; 判定栈的push和pop序列是否对应

出题:输入一个整数,要求计算此整数的二进制表示中1的个数 分析: 如果整数表示为k,当其是负数的时候,使用1<<i分别检测k的每一位:当其位整数的时候,则k/2表示将其二进制表示右移一位,k%2 ==0表示其是否是偶数,如果不是则说明当前二进制表示的最右边一位为1,当k==0成立的时候移位结束: 另外还可以使用'消1'的方法,如果二进制表示A为'****1000',则A-1为'****0111',也就是我们仅关注二进制表示最右边的第一个 1,这样的话A&(A-1)的结果就可以将最右边的

剑指offer11:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。(进制转换,补码反码)

1. 题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 2. 思路和方法 使用移位(<<)和 “| & !”操作来实现.1的二进制是:前面都是0,最后一位为1.每次向左移位一下,使得flag的二进制表示中始终只有一个位为1,每次与n做位与操作,这样就相当于逐个检测n的每一位是否是1.unsigned int flag = 1; 3. C++核心代码 3.1 位运算 1 class Solution { 2 public: 3 int NumberOf1(int

整数的二进制表示中1的个数

给出通常能想到的方式,这两种方式在<C和指针>一书中给出.以下讨论的均为非负整数. /* 该方法每次在循环中判断数的二进制最右一位是否为1(如果该数能不能被2整除). 每次循环后该数右移一位.因此遍历了数的二进制表示的每一位. */ int count_one_bits1(int value) { int count; for (count = 0; value != 0; value >>= 1) if (value % 2 != 0) count++; return count

IT公司100题-28-整数的二进制表示中1的个数

问题描述: 输入一个整数n,求n的二进制表示中,一共有多少个1.例如n=8,二进制表示为00001000,二进制表示中有1个1. 分析: 如果一个数n不为0,那么n-1的二进制表示,与n的二进制表示相比,n的二进制表示最右边的1变为0,而最右边的1所对应的0全部变为1.其余位不受影响. 例如:n的二进制表示为****1000,则n-1的二进制表示为****0111,则n&(n-1)的二进制表示为****0000.将n二进制表示中最右边的1去掉了. 将n赋值为n&(n-1),继续循环此操作,