目录

一.修炼必备

二. 位运算

二.移位运算符

三.位运算综合使用

恭喜你,成功突破至筑基五层!!!


一.修炼必备

1.入门必备:VS2019社区版,下载地址:Visual Studio 较旧的下载 – 2019、2017、2015 和以前的版本 (microsoft.com)

2.趁手武器:印象笔记/有道云笔记

3.修炼秘籍:牛客网 – 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网 (nowcoder.com)

4.雷劫必备:leetcode力扣(LeetCode)官网 – 全球极客挚爱的技术成长平台

注:遇到瓶颈怎么办?百度百科_全球领先的中文百科全书 (baidu.com)

二. 位运算

1.什么是位运算?

——位运算就是直接对整数在内存中的二进制位进行操作的运算

2.位运算操作符

位操作符特点

&(按位与)

有0为0,全1为1

|(按位或)有1为1,全0为0
^(按位异或)相同为0.不同为1
~(按位取反)0变1,1变0

注:

1)二进制的运算均是以补码进行运算的

2)异或满足交换律和结合律

交换律:num ^ 0 = num; 0 ^ num = num;

结合律:num ^ a ^ a = num; a ^ num ^ a = num;

//任何数和0异或等于本身,相同数异或为0

3)只有对整数才能进行位运算,浮点数不能进行位运算

3.一个小case快速了解位运算符

#includeint main(){int a=7;int b=4;//按位与int c=a&b;//00000000 00000000 00000000 00000111 -> a: 7//00000000 00000000 00000000 00000100 -> b: 4//00000000 00000000 00000000 00000100 -> a&b: 4printf("%d & %d = %d\n",a,b,c);// 7 & 4 = 4//按位或c=a|b;//00000000 00000000 00000000 00000111 -> a: 7//00000000 00000000 00000000 00000100 -> b: 4//00000000 00000000 00000000 00000111 -> a|b: 7 printf("%d | %d = %d\n",a,b,c);// 7 | 4 = 7//按位异或c=a^b;//00000000 00000000 00000000 00000111 -> a: 7//00000000 00000000 00000000 00000100 -> b: 4//00000000 00000000 00000000 00000011 -> a^b: 3printf("%d ^ %d = %d\n",a,b,c);// 7 ^ 4 = 3//按位取反c = ~a;//00000000 00000000 00000000 00000111 -> a: 7//11111111 11111111 11111111 11111000 -> ~a(补码)//11111111 11111111 11111111 11110111 -> 反码//10000000 00000000 00000000 00001000 -> 原码(打印的是原码):-8printf("~%d = %d\n", a, c);//~7 = -8return 0;}

4.常用的位操作符

1)判断奇偶性

奇数:(num & 1) == 1 等价于 num % 2 == 1

偶数:(num & 1) == 0 等价于 num % 2 == 0

注:为什么num&1要加括号? —— ==的优先级比&的优先级高

#include int main(){int num = 0;scanf("%d", &num);//若是想要使用num & 1 == 1,则需要使用括号括上(num & 1) == 1if (num & 1){printf("%d是奇数\n", num);}else{printf("%d是偶数\n", num);}return 0;}

2)计算二进制中有几个1:num = num & (num -1)

#include int getOneCount(int num){int count = 0;while (num){num = num & (num - 1);count++;//测试用例1:7//00000000 00000000 00000000 00000111: 7//00000000 00000000 00000000 00000110: 6//00000000 00000000 00000000 00000110: 6 :结果//00000000 00000000 00000000 00000101: 5//00000000 00000000 00000000 00000100: 4: 结果//00000000 00000000 00000000 00000011: 3//00000000 00000000 00000000 00000000: 0: 结果 -->跳出循环//测试用例2:10//00000000 00000000 00000000 00001010: 10//00000000 00000000 00000000 00001001: 9//00000000 00000000 00000000 00001000: 8: 结果//00000000 00000000 00000000 00000111: 7//00000000 00000000 00000000 00000111: 0: 结果 -->跳出循环}return count;}int main(){int num = 0;scanf("%d", &num);int count = getOneCount(num);//计算1的个数printf("%d的二进制中有%d个1\n", num, count);return 0;}

3)num & -num:得到二进制的最低位的1(不一定是最后一位)

#include int main(){int num = 0;scanf("%d", &num);int ret = num & -num;printf("%d & -%d = %d\n", num, num, ret);//说明:二进制的运算均是以补码进行的//测试案例1:7//10000000 00000000 00000000 00000111 -->原码-7//11111111 11111111 11111111 11111000 -->反码//11111111 11111111 11111111 11111001 -->补码//00000000 00000000 00000000 00000111 -->补码7//00000000 00000000 00000000 00000001 --> 1 :结果//测试用例2: 10//10000000 00000000 00000000 00001010 -->原码 -10//11111111 11111111 11111111 11110101 -->反码//11111111 11111111 11111111 11110110 -->补码//00000000 00000000 00000000 00001010 -->补码10//00000000 00000000 00000000 00000010 -->2 : 结果return 0;}

4)num & ~num:0

#include int main(){int num = 0;scanf("%d", &num);int ret = num & ~num;printf("%d & ~%d = %d\n", num, num, ret);//测试用例1:3//00000000 00000000 00000000 00000011 :3//11111111 11111111 11111111 11111100 :~3//00000000 00000000 00000000 00000000 :0 结果//测试用例2:4//00000000 00000000 00000000 00000100 :4//11111111 11111111 11111111 11111011 :~4//00000000 00000000 00000000 00000000 :0 结果return 0;}

5)低位首0变1:num | (num+1)

#include int main(){int num = 0;scanf("%d", &num);int ret = num | (num + 1);printf("%d | %d = %d\n", num, num + 1, ret);//测试用例1:5//00000000 00000000 00000000 00000101 :5//00000000 00000000 00000000 00000110 :6//00000000 00000000 00000000 00000111 : 7 --> 低位首0变1//测试用例2:9//00000000 00000000 00000000 00001001 :9//00000000 00000000 00000000 00001010 :10//00000000 00000000 00000000 00001011 :11 --> 低位首0变1return 0;}

6)求num的相反数:~num + 1

#include int main(){int num = 0;scanf("%d", &num);int ret = ~num + 1;printf("%d\n", ret);//测试用例1:5//11111111 11111111 11111111 11111010 :~5//11111111 11111111 11111111 11111011 :~5 + 1 补码//11111111 11111111 11111111 11111010 :反码//10000000 00000000 00000000 00000101 :原码 --> -5//测试用例2:-5//10000000 00000000 00000000 00000101 原码//11111111 11111111 11111111 11111010 反码//11111111 11111111 11111111 11111011 补码//00000000 00000000 00000000 00000100 ~(-5)//00000000 00000000 00000000 00000101 ~(-5)+ 1 --> 5(结果)return 0;}

7)判断数是不是2的幂:num & (num-1) == 0

#include int main(){int num = 0;scanf("%d", &num);if ((num & (num - 1)) == 0){printf("%d是2的幂\n", num);}else{printf("%d不是2的幂\n", num);}//测试案例1:2//00000000 00000000 00000000 00000010 :2//00000000 00000000 00000000 00000001 :1//00000000 00000000 00000000 00000000 :0 --> 结果//测试用例2:8//00000000 00000000 00000000 00001000 : 8//00000000 00000000 00000000 00000111 : 7//00000000 00000000 00000000 00000000 : 0 -->结果return 0;}

8)异或应用:变量交换

#include int main(){int a = 0;int b = 0;scanf("%d %d", &a, &b);//交换变量a = a ^ b;b = a ^ b;a = a ^ b;printf("%d %d\n", a, b);return 0;}

二.移位运算符

1.什么是移位运算符?

——在C语言中,使用<>对数的二进制位进行向左移动和向右移动,而<>称为移位运算符

2.移位操作符

移位操作符特点
<<左边丢弃,右边补0
>>

算术右移:右边丢弃,左边补符号位

逻辑右移:右边丢弃,左边补0

二进制位进行移位的时候,不要移动负数位,因为这个标准是未定义的

3.一个小case快速了解移位操作符

#include int main(){int num = 7;int ret = num << 2;//00000000 00000000 00000000 00000111num//000000 00000000 00000000 0000011100num <> 2;//00000000 00000000 00000000 00000111num//注:我们在这个地方进行的是算术右移,现在大多数编译器都是进行算术右移的//0000000000 00000000 00000000 000001num >> 2 :1printf("%d\n", ret);//1return 0;}

4.常用的移位操作

1)num >> 1 等价于 num / 2

#include int main(){int num = 0;scanf("%d", &num);int ret = num >> 1;int res = num / 2; //测试案例1:10//00000000 00000000 00000000 00001010num: 10//00000000 00000000 00000000 00000101num >> 1:5//num / 2 = 5//测试案例2:15//00000000 00000000 00000000 00001111num:15//00000000 00000000 00000000 00000111num >> 1:7//num / 2= 7if (ret == res){printf("num>>1和num/2相等\n");}else{printf("num>>1和num/2不相等\n");}return 0;}

2)去掉num的低x位(从最低位一直到x位):num >> x

#include int main(){int num = 0;scanf("%d", &num);int ret = num >> 3;//去掉低三位//00000000 00000000 00000000 00001111num:15//00000000 00000000 00000000 00000001num:1printf("%d\n", ret);//1ret = num >> 2;//去掉低两位//00000000 00000000 00000000 00001111num:15//00000000 00000000 00000000 00000011num:3printf("%d\n", ret);//3return 0;}

三.位运算综合使用

注:规定,我的最低位是从1开始,最高位是32

1.获取num二进制位的第n位值:(num >> n) &1

#include int main(){int num = 0;scanf("%d", &num);int ret = (num >> 3) & 1;printf("%d\n", ret);//测试案例:15//00000000 00000000 00000000 00001111num:15//00000000 00000000 00000000 00000001num >> 3//00000000 00000000 00000000 00000001(num >> 3) & 1//00000000 00000000 00000000 000000011return 0;}

2.将num的第(n+1)位置为1:num | (1 << n)

#include int main(){int num = 0;scanf("%d", &num);//将num的第4位置为1int ret = num | (1 << 3);printf("%d\n", ret);//测试案例:5//00000000 00000000 00000000 00000101//00000000 00000000 00000000 00001000 1 << 3//00000000 00000000 00000000 00001101 13return 0;}

3.将num的第(n+1)位置为0:num & (~(1 << n))

#include int main(){int num = 0;scanf("%d", &num);//将num的第3位置为0int ret = num & (~(1 << 2));printf("%d\n", ret);//测试案例:5//00000000 00000000 00000000 00000100 1 << 2//11111111 11111111 11111111 11111011 ~(1 << 2) :补码//00000000 00000000 00000000 00000101 : 5//00000000 00000000 00000000 00000001 : num & (~(1 << 2))return 0;}

4.获取num的第(n+1)位的幂值:num & (1 << n)

#include int main(){int num = 0;scanf("%d", &num);//获取num第3位的幂值int ret = num & (1 << 2);printf("%d\n", ret);//测试案例 :5//00000000 00000000 00000000 00000101 : 5//00000000 00000000 00000000 00000100 : 1 << 2//00000000 00000000 00000000 00000100 : num & (1 << 2): 4//测试案例: 8//00000000 00000000 00000000 00001000 : 8//00000000 00000000 00000000 00000100 : 1 << 2//00000000 00000000 00000000 00000000 : num & (1 << 2): 0return 0;}

5.将num的最高位到(n+1)位置为0:num & ((1 << n) – 1)

#include int main(){int num = 0;scanf("%d", &num);//将num的最高位到第4位置为0int ret = num & ((1 << 3) - 1);printf("%d\n", ret);//测试案例:121//00000000 00000000 00000000 01111001 :121//00000000 00000000 00000000 00000111 : 1 << 3 - 1//00000000 00000000 00000000 00000001 : 7return 0;}

6.将num的第1位到第(n+1)位置为0:num & (~((1 << (n + 1)) – 1))

#include int main(){int num = 0;scanf("%d", &num);//将num的第0位到第3位置为0int ret = num & (~((1 << (2 + 1)) - 1));printf("%d\n", ret);//测试案例: 121//00000000 00000000 00000000 00000111 :(1 << (2 +1) - 1)//11111111 11111111 11111111 11111000 :~(1 << (2 +1) - 1)//00000000 00000000 00000000 01111001 :121//00000000 00000000 00000000 01111000return 0;}

7.代替减法进行两数相减:x + ~y + 1

#include int main(){int x = 0;int y = 0;scanf("%d %d", &x, &y);int ret = x + ~y + 1;printf("%d - %d = %d\n", x, y, ret);//测试案例:x = 5, y = 3//00000000 00000000 00000000 00000011 y//11111111 11111111 11111111 11111100 ~y//00000000 00000000 00000000 00000101 x//00000000 00000000 00000000 00000001 x + ~y = 1//00000000 00000000 00000000 00000010 x + ~y + 1 = 2//测试案例: x = 3, y = 5//00000000 00000000 00000000 00000101 y//11111111 11111111 11111111 11111010 ~y//00000000 00000000 00000000 00000011 x//11111111 11111111 11111111 11111101 x + ~y//11111111 11111111 11111111 11111110 x + ~y + 1 补码//11111111 11111111 11111111 11111101 反码//10000000 00000000 00000000 00000010 原码 -2return 0;}

8.代替加法进行两数相加:x – ~y – 1

#include int main(){int x = 0;int y = 0;scanf("%d %d", &x, &y);int sum = ~y;int ret = x - ~y - 1;printf("%d + %d = %d\n", x, y, ret);//测试案例:x = 5, y = 3//00000000 00000000 00000000 00000011 y//00000000 00000000 00000000 00000101 x//11111111 11111111 11111111 11111100 ~y//00000000 00000000 00000000 00001001 x - ~y//00000000 00000000 00000000 00001000 x - ~y - 1: 8return 0;}

注:位运算的基本常用的操作就在这点了,但是远不止这点,需要我们更加努力的学习和探索位运算的奥妙。

注:若是觉得CSDN看起来很难受的话,请去有道云看我写的原文(排版更好)

链接在此:有道云笔记

恭喜你,成功突破至筑基五层!!!