关于位运算

事实上位运算对于我自己来讲 它就可以理解为一种二进制的算法吧 它就纯粹的在二进制下的运作

相当于说比如当我在执行 类似 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进行异或 那就出来了他本身 

这个题目很巧妙的运用了异或的特性以及思想

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值