当前位置:首页 » 《随便一记》 » 正文

筑基五层 —— 位运算看这篇就行了

28 人参与  2023年03月29日 12:17  分类 : 《随便一记》  评论

点击全文阅读


目录

一.修炼必备

二. 位运算

二.移位运算符

三.位运算综合使用

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


一.修炼必备

 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看起来很难受的话,请去有道云看我写的原文(排版更好)

  链接在此:有道云笔记

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


点击全文阅读


本文链接:http://zhangshiyu.com/post/57016.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1