因为在前天的练习题中,涉及到了位运算,但我之前对位运算了解的不多,就查找总结了一下,写了这篇博客,巩固一下所学
C语言之位运算
一、位运算符
逻辑运算符 | 操作 | 移位运算符 | 操作 |
---|
& | 按位 “与” | a << b | a左移b位 | ^ | 按位 “异或” | a >> b | a右移b位 | | | 按位 “或” | | | ~ | 按位 “非”(取反) | | |
PS:都是以位(bit)为单位
二、位运算
1. & 按位“与”运算
#include<stdio.h>
#include<stdlib.h>
int main(){
unsigned char num1 = 170;
unsigned char num2 = 85;
unsigned char num3 = num1 & num2;
printf("num1 = %d \n", num1);
printf("num2 = %d \n", num2);
printf("num3 = %d \n", num3);
return 0;
}
运行结果:
2. ^ 按位异或运算
#include<stdio.h>
#include<stdlib.h>
int main(){
unsigned char num1 = 170;
unsigned char num2 = 85;
unsigned char num3 = num1 ^ num2;
printf("num1 = %d \n", num1);
printf("num2 = %d \n", num2);
printf("num3 = %d \n", num3);
return 0;
}
运行结果:
3. | 按位或运算
#include<stdio.h>
#include<stdlib.h>
int main(){
unsigned char num1 = 42;
unsigned char num2 = 21;
unsigned char num3 = num1 | num2;
printf("num1 = %d \n", num1);
printf("num2 = %d \n", num2);
printf("num3 = %d \n", num3);
return 0;
}
运行结果:
4. ~ 按位取反(非运算)
#include<stdio.h>
#include<stdlib.h>
int main(){
unsigned short num1 = 255;
unsigned short num2 = ~num1;
unsigned short num3 = ~num2;
printf("num1 = %d \n", num1);
printf("num2 = ~num1 = %d \n", num2);
printf("num3 = ~num2 = %d \n", num3);
return 0;
}
运行结果:
5. >> 右移
#include<stdio.h>
#include<stdlib.h>
int main(){
unsigned char num1 = 32;
unsigned char num2 = num1 >> 1;
unsigned char num3 = 64;
num3 >>= 2;
printf("num1 = %d \n", num1);
printf("num2 = ~num1 = %d \n", num2);
printf("num3 = ~num2 = %d \n", num3);
return 0;
}
运行结果:
6. << 左移
#include<stdio.h>
#include<stdlib.h>
int main(){
unsigned char num1 = 32;
unsigned char num2 = num1 << 2;
unsigned char num3 = 8;
num3 <<= 3;
printf("num1 = %d \n", num1);
printf("num2 = ~num1 = %d \n", num2);
printf("num3 = ~num2 = %d \n", num3);
return 0;
}
运行结果:
三、位运算符优先级
优先级 | 运算符 | 结合方向 |
---|
1 | - (符号运算符), ~ (取反运算符), ++ (自增), -- (自减) | 从右向左 | 2 | * (乘), / (除), % (取余) | 从左向右 | 3 | + (加), - (减) | 从左向右 | 4 | << (左移), >> (右移) | 从左向右 | 5 | > (大于), < (小于), >= (大于等于), <= (小于等于) | 从左向右 | 6 | == (等于), != (不等于) | 从左向右 | 7 | & (按位与) | 从左向右 | 8 | ^ (按位异或) | 从左向右 | 9 | | (按位或) | 从左向右 |
四、位运算应用
功能 | 位运算操作 | 示例 |
---|
去掉最后一位 | x >> 1 | 0010 -> 0001 | 在最后加一个0 | x << 1 | 0100 ?> 1000 | 在最后加一个1 | x<<1+1 | 0100 ?> 1001 | 将最后一位变为1 | x | 1 | 0100 ?> 0101,即和0…01相与,与0为0,与1为1 | 将最后一位变为0 | x|1 - 1 | 0101 ?> 0100, 这里实际上就是先确保最低位变为1,再减去1 | 最后一位取反 | x ∧ 1 | 0100 ?> 0101, 利用异或性质,其中除最后一位其余不变 | 把右数的第k位变为1 | x | (1<<(k - 1)) | 0001 ?> 1001,k=4,即将第k位和1相或为1 | 把右数的第k位变为0 | x & ~(1<<(k ? 1)) | 1001 ?> 0001, k=4, 这个操作实际上就是先将第k位变为1,然后取反得到第k位为0,其余位为1,最后利用按位与的性质其余位不变,第k位与0得0 | 把右数的第k位取反 | x ∧ (1<<(k ? 1)) | 1000?>0000,k=4,利用异或性质 | 取末k位 | x & (1<<k ? 1) | 1011?>0011,k=2,即先得到0100,再-1得到0011,然后与x相与(得到一个后k为1,其余为0的数,再与x相与) | 取右数的第k为 | x>>(k-1)&1 | 1000->0001,k = 4,右移k-1位则是去掉最后的k-1位,然后按位与1即可提出最后一位,即第k位 | 把末k位全变为1 | x | (1<<k - 1) | 1000?>1111, k=3,即与k位1相或 | 把右边连续的1变为0 | x & (x+1) | 0111-> 0000, 右起连续的1 | 把右起的第一个0变为1 | x|(x+1) | 0011->0111 | 右起连续的0变成1 | x|(x-1) | 1000 -> 1111 | 取右边连续的1 | (x ^ (x + 1))>>1 | 1011->0011 | 将右起第一个1的左边全变成0 | x & (x ^ (x - 1)) | 1101-> 0001 |
原题目如下:
Leetcode-342
【描述】输入一个表示整数的字符串,判断这个字符串是否为4的幂
【输入】一个正整数字符串
【输出】返回true或false
【进阶】尽量不使用循环或递归来实现
4的幂次方一定是2的幂次方,但是反过来却不成立。例如,8是2的3次方,但并不是4的幂次方。
1转成2进制是1; 4转成2进制是100; 16转成2进制是10000; 64转成2进制是1000000;
4的幂次方的规律就是看这个数转成2进制后是不是所有位数只有1个1,并且这个1只能在奇数位上出现。
code:
class Solution {
public:
bool isPowerOfFour(int num) {
if(num == 1) return true;
if(num <= 3) return false;
int count = 0;
int i = 1;
while(num != 0){
if((num&1) != 0 && (i&1) != 0){
count++;
}
if((i&1) == 0 && (num&1) != 0){
return false;
}
num >>= 1;
i ++;
}
if(count == 1)
return true;
return false;
}
};
位运算相较于循环嵌套等方法会简单一些
|