目录
前言
位运算的基本操作与经典应用问题。
一、位运算符与位运算基本操作
1.位运算符
&(与): 相同位数只有同为1,结果才为1,其余为0
|(或):相同位数有一个为1,结果为1,其余为0
~(非):位数取反
^(异或):两者不同时结果为1,可视为不进位的二进制加法, 两个相同数异或为0
>> (右移位运算符):高位以符号位填充
<< (左移位运算符):
>>>运算符:高位填充0
特别注意:没有<<<运算符,当进行移位操作时可能会因为数据本身的数据类型存储表示范围而溢出。
2.基本位运算的操作
- 判断奇偶数: x & 1 , = 1为奇数, = 0为偶数
- 获取二进制位是1还是0:移位操作 + &
- 交换两个整型变量的值: 三次^异或运算
- 不用判断语句,求整数绝对值:(a + (a >> 31)) ^ (a >> 31)
- K个相同的k进制数做不进制加法,结果为0
二、经典应用问题
1.找出唯一成对的数
题目:1~1000这1000个数放在含有1001个元素的数组中,找出唯一成对的元素。
分析:利用相同两个数异或为0,消除重复的数。用变量s先异或一个无重复的序列,再用此异或序列结果异或重复序列。时间O(n),空间O(1)
代码如下(示例):
#include<bits/stdc++.h>
using namespace std;
int findNum(int a[], int n){
int s = 0;
for(int i = 1; i < n; i++)
s = s ^ i; // s = 1 ^ 2 ^ 3 ^...^ n - 1(1000)
for(int i = 0; i < n; i++){
s = s ^ a[i];
}
return s;
}
void show(int a[], int n){
for(int i = 0; i < n; i++){
if( i == n - 1){
cout << a[i] << endl;
break;
}
cout << a[i] << " "; // 打印查看
}
}
void Swap(int &a, int &b){
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
int main(){
int n = 1001;
int* p = new int[n];
if(!p) cout << "error" << endl;
for(int i = 0; i < n - 1; i++)
p[i] = i + 1;
cout << "error1" << endl;
srand((unsigned)time(NULL));//time()用系统时间初始化种。为rand()生成不同的随机种子。
p[n - 1] = rand() % (n - 1) + 1; // 从1 ~ 1000随机最后一个元素
int index = rand() % n;
Swap(p[index], p[n - 1]);
show(p, n);
int ans = findNum(p, n);
cout << ans << endl;
return 0;
}
2.二进制中1的个数
问题:输入一个整数,输出整数转化为二进制后1的个数。
分析:
1.采用按位移动依次取出每位与1比较,若为真,个数++
2.减去1,从末尾最近的1到末尾最后一位因为借位变反,这是只需与原始数据&,保留前面部分,舍去后面部分(变为0)
代码如下(示例):
int n = 45;
int Count = 0;
while(n){
n = (n - 1) & n;
Count++;
}
cout << Count << endl;
3.判断整数是否为2的整数次方
转化为判断整数二进制是否只有一个1
4.整数奇偶位互换
int Change(int n){
int j = n & 0x55555555; //和0101 0101...做与运算取出奇数位
int o = n & 0xaaaaaaaa; //和1010 1010...做与运算取出偶数位
retunr (j >> 1) | (o << 1);
}
5.0~1间浮点实数的二进制表示
整数转二进制:除2,取余,判断商是否为0作为终止
小数转二进制:乘2,取整,整数位归0,小数点继续循环
6.出现1次与出现K次
题目:数组中只有一个数出现1次,其余数出现k次,找出出现1次的那个数。
规律:K个相同的k进制数做不进制加法,结果为0
题解:所有数转换为K进制再依次异或,结果就为剩余的那个出现1次的数的K进制。
总结
二进制记录