事实上位运算对于我自己来讲 它就可以理解为一种二进制的算法吧 它就纯粹的在二进制下的运作
相当于说比如当我在执行 类似 x&1的操作时 我要先把左右两边都换成二进制之后 然后开始我接下来的操作 至于中间的这个类似&的符号 是随着题目的变换而变换的 接下来就说一下这些符号的基本含义
&:与运算 当两者都为1时,结果即为1,否则为0;
| :或运算 当两者都为0时,结果为1,否则为0;
^:异或运算 当两者同时为0或1时,结果为0,否则为1;
对于A<<B ,我们表示把A转化为二进制之后向左移动B位(在末尾添加B个0)
对于A>>B, 我们表示把A转化为二进制之后向右移动B位(删除末尾的B位)
比如2<<2 ,将2转化为二进制之后为10 ,那么10向左移动2位 变成了二进制1000,转化为十进制就是8,所以2<<2=8;
以上就是位运算的一些基本操作 若有缺漏会及时补上
可能有些人会问,位运算的这些操作有什么意义 对于计算机来讲 它的底层就是通过二进制来进行展开计算的 所以当我们用位运算来写的时候 对于计算机本身来讲 他的计算会更加迅速 所以当我们平时写题目的时候会遇到的一些时间复杂度较严的题目 一般方法一直超时的情况下 位运算在此时会是一个很好的解决方案
1.判断奇偶
#include<bits/stdc++.h>
using namespace std;
//判断奇偶性
bool cmp1(int n) {
return (n & 1) == 1;
}
int main() {
int n;
cin >> n;
if (bool(n)) {
cout << "odd";
}
else {
cout << "even";
}
return 0;
}
这里面的cmp1的函数就是来判断奇偶 至于是什么原理呢 这个就是跟二进制的位运算有关了
众所周知 我们判断奇偶性的通常方式是将这个数字除以2然后看看有没有余数
但是在位运算这边呢 我们可以巧妙的运用与运算(&)的特性来进行计算
我们知道 二进制有一个特点 比如说10的二进制是1010 9的二进制是1001 我们可以看出 如果一个数它是奇数的话 那么二进制的最后一位是1 否则就是0 那么我们就可以将某个数与1来进行与运算
因为1的二进制是00000001 在前七位进行与运算时,不论你想要判断的那个数的那个位置上是0还是1,由于1的二进制的这一位已经是0,所以都是0
在最后一位进行判断的时候 是否是1取决于判断的那个数的最后一位是否为0 若是0 那么最后的结果就是0 此时这个数也就是偶数 ;反之则是1 说明判断的数字是奇数。
2.交换两个整数变量的值
#include<bits/stdc++.h>
using namespace std;
//交换两个整数变量的值
int main() {
int a, b;
while (cin >> a >> b) {
a = a ^ b;
b = a ^ b;//b=(a^b)^b=a^(b^b)=a;
a = a ^ b;//a=a^b^a
cout << a << " " << b<<"\n";
}
return 0;
}
这个交换我们平时就是直接一个swap就可以完成交换两个数很方便
但我们这边是通过位运算里面的异或的一个特性 我在代码那边也写出来了 这个究竟是怎么一回事 为什么三个异或就能让两个整数进行交换?
首先一开始的a=a^b 这个没有特殊含义
我们看第二步: b=a^b 首先我们要知道 这里面的a已经不是我们原来的那个a了 它已经变成了a^b (这个a^b才是我们最一开始的a和b)那这时候的b就相当于是b=a^b^b 我们可以知道的是 b^b是0 然后任何数异或0都是它本身 所以最后的b=a^0=a 这个时候我们就已经将a的值给赋值到b里面去了
然后我们看最最后一步: a=a^b 我们还是把这个式子里面所谓的a和b转化为我们最一开始的a和b
首先 式子右边的a=a^b 这个是第一个式子的结果 在第一个式子里 a就是a b就是b 他还没经过第二步 所以这里的b就是b 然后右边的b已经换过来了 所以是a 所以整个式子就是 a=a^b^a 跟上面一样最后的结果就是 a=b
(但是位运算的交换数字只适合用于整数类型的数字 对于小数时不能用来进行交换的)
3.判断a的第k位二进制是0还是1
#include<bits/stdc++.h>
using namespace std;
int main() {
int a,k;
while (cin >> a >> k) {
if (a >> (k - 1) & 1) {
cout << 1;
}
else {
cout << 0;
}
}
return 0;
}
这个题目就是跟奇偶数那题用到了一个相同的与运算 原理是什么呢
当我将一个十进制的数字转化为二进制 比如说9的二进制为1001 然后我想看它第2位是0还是1
这个时候我们就要用到右移这个动作
我们想看第2位的数字是0还是1 那么我们就右移一位 这个时候这个数字就变成了100 然后这个时候我们把它与1进行&(与运算) 如果第2位上面的数字是0 那么进行运算之后 结果就是0 反之为1
所以我们可以看到 第一步 判断第k位的数字是否为0还是1 我们先把这个数的二进制向右移动k-1个单位 然后与1进行与运算即可
4.找重复出现2次的数字
题目规定一个数组有n+1个数字 里面分布的数字大小是从1-n 其中除了一个数字出现两次之外其他都只出现一次
#include<bits/stdc++.h>
using namespace std;
const int N = 5;
int main()
{
int ans = 1;
for (int i = 1; i <= N; i++) {
ans ^= i;
}
for (int i = 1; i <= N + 1; i++) {
int x;
cin >> x;
ans ^= x;
}
cout << ans;
return 0;
}
这题也是运用异或的特性 已知在一堆数里 只有一个重复了 那我把所有从1-n的数字都异或一遍之后 我们假设这个数字为x 然后我们再把这个x与这1-n+1的数字进行异或 已知其中n个数字为1-n
那么这n个数字与x异或之后为0(因为相同的数字进行异或之后为0) 那么接下来重复的那个数字与0进行异或 那就出来了他本身
这个题目很巧妙的运用了异或的特性以及思想