目录
一.修炼必备
二. 位运算
二.移位运算符
三.位运算综合使用
恭喜你,成功突破至筑基五层!!!
一.修炼必备
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快速了解位运算符
#include<stdio.h>int 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: 4 printf("%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: 3 printf("%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 -> 原码(打印的是原码):-8 printf("~%d = %d\n", a, c);//~7 = -8 return 0;}
4.常用的位操作符
1)判断奇偶性
奇数:(num & 1) == 1 等价于 num % 2 == 1
偶数:(num & 1) == 0 等价于 num % 2 == 0
注:为什么num&1要加括号? —— ==的优先级比&的优先级高
#include <stdio.h>int main(){ int num = 0; scanf("%d", &num); //若是想要使用num & 1 == 1,则需要使用括号括上(num & 1) == 1 if (num & 1) { printf("%d是奇数\n", num); } else { printf("%d是偶数\n", num); } return 0;}
2)计算二进制中有几个1:num = num & (num -1)
#include <stdio.h>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 <stdio.h>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 <stdio.h>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 <stdio.h>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变1 return 0;}
6)求num的相反数:~num + 1
#include <stdio.h>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 <stdio.h>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 <stdio.h>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 <stdio.h>int main(){ int num = 7; int ret = num << 2; //00000000 00000000 00000000 00000111 num //000000 00000000 00000000 0000011100 num << 2 :28 printf("%d\n", ret);//28 ret = num >> 2; //00000000 00000000 00000000 00000111 num //注:我们在这个地方进行的是算术右移,现在大多数编译器都是进行算术右移的 //0000000000 00000000 00000000 000001 num >> 2 :1 printf("%d\n", ret);//1 return 0;}
4.常用的移位操作
1)num >> 1 等价于 num / 2
#include <stdio.h>int main(){ int num = 0; scanf("%d", &num); int ret = num >> 1; int res = num / 2; //测试案例1:10 //00000000 00000000 00000000 00001010 num: 10 //00000000 00000000 00000000 00000101 num >> 1:5 //num / 2 = 5 //测试案例2:15 //00000000 00000000 00000000 00001111 num:15 //00000000 00000000 00000000 00000111 num >> 1:7 //num / 2= 7 if (ret == res) { printf("num>>1和num/2相等\n"); } else { printf("num>>1和num/2不相等\n"); } return 0;}
2)去掉num的低x位(从最低位一直到x位):num >> x
#include <stdio.h>int main(){ int num = 0; scanf("%d", &num); int ret = num >> 3;//去掉低三位 //00000000 00000000 00000000 00001111 num:15 //00000000 00000000 00000000 00000001 num:1 printf("%d\n", ret);//1 ret = num >> 2;//去掉低两位 //00000000 00000000 00000000 00001111 num:15 //00000000 00000000 00000000 00000011 num:3 printf("%d\n", ret);//3 return 0;}
三.位运算综合使用
注:规定,我的最低位是从1开始,最高位是32
1.获取num二进制位的第n位值:(num >> n) &1
#include <stdio.h>int main(){ int num = 0; scanf("%d", &num); int ret = (num >> 3) & 1; printf("%d\n", ret); //测试案例:15 //00000000 00000000 00000000 00001111 num:15 //00000000 00000000 00000000 00000001 num >> 3 //00000000 00000000 00000000 00000001 (num >> 3) & 1 //00000000 00000000 00000000 00000001 1 return 0;}
2.将num的第(n+1)位置为1:num | (1 << n)
#include <stdio.h>int main(){ int num = 0; scanf("%d", &num); //将num的第4位置为1 int ret = num | (1 << 3); printf("%d\n", ret); //测试案例:5 //00000000 00000000 00000000 00000101 //00000000 00000000 00000000 00001000 1 << 3 //00000000 00000000 00000000 00001101 13 return 0;}
3.将num的第(n+1)位置为0:num & (~(1 << n))
#include <stdio.h>int main(){ int num = 0; scanf("%d", &num); //将num的第3位置为0 int 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 <stdio.h>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): 0 return 0;}
5.将num的最高位到(n+1)位置为0:num & ((1 << n) - 1)
#include <stdio.h>int main(){ int num = 0; scanf("%d", &num); //将num的最高位到第4位置为0 int 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 : 7 return 0;}
6.将num的第1位到第(n+1)位置为0:num & (~((1 << (n + 1)) - 1))
#include <stdio.h>int main(){ int num = 0; scanf("%d", &num); //将num的第0位到第3位置为0 int 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 01111000 return 0;}
7.代替减法进行两数相减:x + ~y + 1
#include <stdio.h>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 原码 -2 return 0;}
8.代替加法进行两数相加:x - ~y - 1
#include <stdio.h>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: 8 return 0;}
注:位运算的基本常用的操作就在这点了,但是远不止这点,需要我们更加努力的学习和探索位运算的奥妙。
注:若是觉得CSDN看起来很难受的话,请去有道云看我写的原文(排版更好)
链接在此:有道云笔记