一、位运算符
1. 位运算符简介
- 位运算符主要作用于位,是逐位进行操作。最常用的有:与 &、或 |、异或 ^。
- 常见的位运算符有(假设变量 A = 60,变量 B =13)
2. 为什么要使用位运算符
- C 语言位运算符在某些编程中如果灵活应用,则可以大大提高程序的执行效率,使程序执行时速度更高。
- C 语言主要应用于嵌入式开发、智能电器、通信行业等一些对效率和时间都要求很高的应用领域中,学好位运算符,在程序开发中灵活应用位运算符,往往能在这些应用中起到事半功倍的效果。
3. 与运算符
- 负数按补码形式参加按位与运算。
- 清零:如果想将一个单元清零,即使其全部二进制位为 0 ,只要与一个各位都为 0 的数值相与,结果为零。
取一个数的指定位:取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低 4 位为1,其余位为0,即Y=0000 1111,然后将 X 与 Y 进行按位与运算即可得到 X 的指定位。
判断奇偶:根据最末位是 0 还是 1 来决定,为 0 就是偶数,为 1 就是奇数。因此可以用 if((a & 1) == 0)代替 if(a % 2 == 0)来判断a是不是偶数。
4. 或运算符
- 负数按补码形式参加按位与运算。
将一个数据的某些位设置为 1:取数 X=1010 1110 的低4位设置为1,只需要另找一个数 Y,令 Y 的低 4 位为 1 ,其余位为 0,即 Y=0000 1111,然后将 X 与 Y 进行按位或运算即可
5. 异或运算符
- 翻转指定位:取数 X=1010 1110 的低 4 位进行翻转,只需要另找一个数 Y ,令 Y 的低 4 位为 1 ,其余位为 0 ,即 Y=0000 1111,然后将X与Y进行异或运算即可。
- 与 0 相异或值不变。
- 交换两个数:
void Swap(int &a, int &b) { if (a != b) { a ^= b; b ^= a; a ^= b; } }
6. 取反运算符
- 如对 a 按位取反,则得到的结果为 -(a+1) 。
- 对正数、负数和零都适用。
7. 左移运算符
- 左边的二进制位丢弃,右边补 0 。
- 若左移时舍弃的高位不包含 1,则每左移一位,相当于该数乘以 2。
8. 右移运算符
- 正数左补 0,负数左补 1,右边丢弃。
- 操作数每右移一位,相当于该数除以 2。
二、位运算例题——二进制中1的个数
题目描述
给定一个长度为 n 的数列,请你求出数列中每个数的二进制表示中 1 的个数。
输入格式
输入共两行。
第一行包含整数 n。
第二行包含 n 个整数,表示整个数列。
输出格式
共一行,包含 n 个整数,其中的第 i 个数表示数列中的第 i 个数的二进制表示中 1 的个数。
数据范围
1 ≤ n ≤ 100000
0 ≤ 数列中元素的值 ≤ 1e9
输入样例
5
1 2 3 4 5
输出样例
1 1 2 1 2
具体实现
1. 方法一(模板)
1.1 代码注解
- for(int i=x;i;i-= i&-i)
- i 表示 i 为真时继续执行。
- i-= i&-i 表示 i = i - (i&-i)。
- i & (-i) 表示的2^k,其中 k 表示 i 中从低位到高位的第一个 1 的位索引。
1.2 实现代码
#include <bits/stdc++.h> using namespace std; int main() { int n; cin>>n; while(n--) { int x; int res=0; cin>>x; for(int i=x;i;i-= i&-i) { res++ ; } cout<<res<<" "; } system("pause"); return 0; }
2. 方法二( lowbit )
1.1 实现思路
lowbit(x) 是 x 的二进制表达式中最低位的 1 所对应的值。
使用 lowbit 操作,每次 lowbit 操作截取一个数字最后一个 1 后面的所有位,每次减去 lowbit 得到的数字,直到数字减到 0 ,就得到了最终 1 的个数。
根据计算机负数表示的特点,如一个数字原码是 1000 1000 ,他的负数表示形式是补码,就是反码 +1 ,反码是 0111 0111 ,加一则是 0111 1000 ,二者按位与得到了1000 ,就是我们想要的 lowbit 操作。
1.2 实现代码
#include<bits/stdc++.h> using namespace std; int lowbit(int x) { return x&(-x); } int main() { int n; cin>>n; while(n--) { int x; cin>>x; int res=0; while(x) { x-=lowbit(x); res++; } cout<<res<<' '; } system("pause"); return 0; }
3. 方法三(暴力枚举)
1.1 实现思路
- 对于每个数字a,a &1得到了该数字的最后一位,之后将a右移一位,直到位0,就得到了1的个数。
1.2 实现代码
#include <bits/stdc++.h> using namespace std; int n; int a,k; int main() { cin>>n; for(int i=0;i<n;i++) { cin>>a; k=0; while(a) { k+=a&1; a=a>>1; } cout<<k<<" "; } system("pause"); return 0; }