文章目录
位运算
位运算的操作对象只能为整型或字符型数据,位运算把运算对象看作是二进制,按位完成指定的运算
位运算直接对内存进行操作,灵活使用可以简化和优化很多程序
1.位运算符号
符号 | 含义 |
---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
<< | 左移 |
>> | 右移 |
~ | 取反 |
按位与 &
指将参加运算的数字,按二进制位进行“与”运算
规则:
0 & 0=0 0 &1=0
1 & 0=0 1 & 1=1
即:两位同时为 1 ,结果才为 1 ,否则为 0
例: 3&5 即 0000 0011 & 0000 0101 = 0000 0001 因此, 3&5 的值得 1
按位或 |
指参加运算的两个数字,按二进制位进行“或”运算
规则:
0|0=0 0|1=1
1|0=1 1|1=1
即 :两位只要有一个为 1 ,其值为 1 ,否则为 0
例: 3|5 即 0000 0011 | 0000 0101 = 0000 0111 因此, 3|5 的值得 7
按位异或 ^
指参加运算的两个数字,按二进制位进行“异或”运算
规则:
0 ^ 0=0 0 ^ 1=1
1 ^ 0=1 1 ^ 1=0
即:两位值不同,则结果为 1 ,否则为 0
例: 3^5 即 0000 0011 ^ 0000 0101 = 0000 0110 因此, 3^5 的值得 6
左移 <<
左移运算是用来将一个数的各个二进制位左移 n 个单位, n 由右操作数指定,左移后其右边空出的位用 0 替补,高位左移溢出则直接舍弃
特别的,在高位没有 1 的情况下,左移 1 位相当于该数乘以 2 ,左移 2 位相当于该数乘以 4 ,15<<2=60 ,即 15 乘了 4 ,但此结论只适用于该数左移时被溢出舍弃的高位中不包含 1 的情况
例: 143<<2 结果为 60 因为 143 转换为进制为 10001111 ,左移 2 得 00111100 ,结果为 60
右移 >>
右移运算符是用来将一个数的各二进制位右移 n 个单位, n 由右操作数指定,移到右端的低位被舍弃,同时高位补 0
取反 ~
按位取反运算符是指将整数的各个二进制位都取反,即 1 变为 0 , 0 变为 1
例:~9=-10 ,因为 9(00001001) 所有位取反即为 (11110110) ,这个数最高位是 1 ,所以是补码,补码还原成反码(反码等于补码减 1 )得到 (11110101) ,再还原为原码(反码到原码最高位不变,其它各位取反)等于 (10001010) , 十进制为 -10
2.用法
(1). 判断奇偶数
int f(int num){
if(num&1)
return 0;//奇数
else
return 1;//偶数
}
(2). 判断2的幂次方
int f(int num){
if(num&(num-1))
return 0;
else
return 1;
}
(3). 计算一个数的二进制中 1 的个数
//一
int f(int num){
int ans=0,n=1;
while(n){
if(num&n)ans++;
n<<=1;
}
return ans;
}
//二
int f(int num){
int ans=0;
while(num){
num=num&(num-1);
ans++;
}
return ans;
}
(4). 对于异或^
异或的性质:
- 交换律:a^b =b^a
- 结合律:( a^b ) ^ c = a ^( b^c )
特别的,任何数与 0 异或都保留原值 a ^ 0 = a
相同的数异或得到 **0 ** a ^ a = 0 a ^ b ^ b = a
交换两个数:
a = a^b; b = b^a; a = a^b;
实例:给出 n 个整数,n 为奇数,其中有且仅有一个数出现了奇数次,其余的数都出现了偶数次。用线性时间复杂度、常数空间复杂度找出出现了奇数次的那个数
#include<iostream>
using namespace std;
int main(){
int n,ans=0,num;
cin>>n;
while(n--){
cin>>num;
ans^=num;
}
cout<<ans<<endl;
return 0;
}