位运算与操作符应用
一.二进制与进制转化
1.概念解析
我们常常能听见2进制,8进制,16进制这些讲法。他们都是数值的不同表达形式。根据不同的进制大小有着不同的权重比例。我们生活中常用的是10进制数,也就是逢10进1,由此推理至其他进制。例如2进制就是逢2进1。
2.进制转化
(1)10进制转化为2进制
如图将10进制的数不断对进制数进行取模,之后在将数除等原数,周而复始,最后将输出数导致就是原数转换的进制数。
(2)2进制转8进制
8进制中每一位都是0~7中的数字,0~7的数字各自写成2进制位最多有3个就足够了。所以我们将二进制位转换时,每次只需3位3位的进行转化。
(3)2进制转16进制
与上文同理,16进制位是由0~9,A~F直接的数组成的,用2进制表示最多只有4位。
3.相关技巧与用法
例如给定x进制,x进制形式的数s,要将其转换为z进制形式。
思路为先将x进制的数s转化为10进制形式,再将该数转化为z进制形式。
将x进制的s转化为10进制形式有两种方法:
(1)逐位相乘法
int main()
{
int x;
int i = 0;
string s;
int ret = 0;
cin >> x >> s;
int n = s.size() - 1;
while (n >= 0)
{
if (s[n] <= '9')
{
ret += (s[n--] - '0') * pow(x, i);
}
else
{
ret += (s[n--] - 'A' + 10) * pow(x, i);
}
i++;
}
cout << ret;
return 0;
}
将每一位的数乘对应的权重转化为10进制相加。
(2)库函数调用
#include <string>
int main()
{
int x;
string s;
cin >> x >> s;
int ret = stoi(s, nullptr, x);
cout << ret;
return 0;
}
这里调用了stoi函数(string to int),将字符串转换为int形式,有三个参数,stoi(const string& str, size_t* idx = 0, int base = 10);
。第一个参数为需要转化的字符串,第二个是一个指针,指向停止转化的字符;第三个参数是需要转换的进制(默认情况为10进制)。
在这里我们将字符串s转化为x进制。
(3)将10进制转化为z进制
string s = "0123456789ABCDEF";
void print(int ret, int m)
{
if (ret > m)
{
print(ret / m, m);
}
cout << s[ret % m];
}
这里我们将10进制数设置为ret,需要转换的进制为m进制。我们使用一个递归,参照上面的(10进制转化为2进制的思路)。
二.位运算
1.概念解析
这里就做一些简单的介绍,重点内容在于后序的运用方法。
(1)左移右移操作符
最高的符号位不变,左移将二进制数整体左移动一位右边补0;右移将二进制整体右移一位,此时分为两种情况。如果是逻辑右移则左边用0进行填充,若是算术右移则左边用符号位进行填充。
(2)&(按位与) |(按位或) ^(按位异或) ~(按位取反)
例a&b当a与b二进制位上都为1,得到的结果为1,否则为0。
例a|b当a与b二进制位上有1则为1,否则为0。
例a^b当a与b二进制位上相同则为0,不相同则为1。
例~a,将1变为0,将0变为1。
这里有个小tips:
所有的二进制操作都是先转化为补码的形式展开的,正数的原码反码补码都相同,负数将原码取反加1(符号位不变)得到的就是补码。
2.位运算的应用
(1)保留二进制位中的指定位
有时候我们希望取出二进制中的某一位,使其他位变为0。我们只需要将对应的位进行(x&m)处理。
(2)获取二进制中的指定位
(3)将指定二进制位设置为1
(4)将指定二进制位设置为0
我们需要对指定位置设置为0,只需要对该位进行&1处理,而其他位需要&0处理。所以我们先将1移动到要置为0的位置,再按位取反,这样就只有该位得到0其余位都为1。
(5)反转指定二进制位
使用一个数m,使得m的二进制位中的第i位为1其余设置为0,然后将(x^m)得到反转后的值。
由于按位取反中,若原数第i位为1,相同异或取反后变为0,若原数为0,与1异或取反后为1。
(6)将二进制位最右边的1变为0
我们可以使用x &(x-1)的方法x - 1让有1的最低的一位变为了0,而其他位不会改变。将其进行&,就可以消去最右边的那一位1。
我们可以通过 x &(x-1)的计算消除一位1,那么如果我们对一个数不断的进行消除1的操作,套上一个循环,就能计算出这个二进制数中1的个数。
一些其他用途:
这种思路有一个专有名词叫做位图(bitmap)。位图是数据结构操作系统常用的数据结构,他可以高效的快速释放资源
(7)只保留二进制位中最右边的1
(8)异或的巧用
相同的两个数异或的结果为0;0与任何数x异或的结果为x;同时异或满足交换律a^b^a == a^a^b;