C++少儿编程(18)位运算

XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

位运算概述XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

 

 XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

位运算是直接对内存中的二进制位进行操作的运算,是底层编程和高性能计算常用的技术。C++提供了6种位运算符:XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. & :按位与(与运算)XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  2. | :按位或(或运算)XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  3. ^ :按位异或(异或运算)XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  4. ~ :按位取反(取反运算)XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  5. << :左移(左移运算)XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  6. >> :右移(右移运算)XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

 XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【位运算符的优先级】XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. 最高优先级:~(按位取反),它是单目运算符;
  2. 其次是:<<(左移)、>>(右移);
  3. 接着是:&(按位与);
  4. 再接着是:^(按位异或);
  5. 最后是:|(按位或)。
 
【注意】位运算只适用于整数类型(如 int、char、long 等),不能用于浮点类型。

位运算符详解XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

 

一、按位与 (&):XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【运算规则】两位同时为1结果才为1,否则结果为0。XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【示例程序】XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库
 XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. int a = 5;      // 0101 
  2. int b = 3;      // 0011 
  3. int c = a & b;  // 0001 (1) 

【应用案例】XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

1、判断奇偶:若 (n & 1) == 0,则 n 为偶数;XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

2、清零特定位:n & ~(1 << k),将第 k 位清零。XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

 

二、按位或 (|):XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【运算规则】两位中只要有一位为1,结果就为1,否则结果为0。
【示例程序】
  1. int a = 5;       // 0101 
  2. int b = 3;       // 0011 
  3. int c = a | b;   // 0111 (7) 
【应用案例】
设置特定位:n | (1 << k) ,将第 k 位设为1。
 

三、按位异或 (^):XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【运算规则】两位不同时结果为1,相同时结果为0。
【示例程序】
  1. int a = 5;       // 0101 
  2. int b = 3;       // 0011 
  3. int c = a ^ b;   // 0110 (6) 
【特性】
1、a ^ a = 0;
2、a ^ 0 = a;
3、满足交换律和结合律。
【应用案例】
1、交换两个数:a ^= b;b ^= a;a ^= b;
2、找唯一不重复的数字(其他数字都出现两次)。
 

四、按位取反 (~):XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【运算规则】0变1,1变0。
【示例程序】
  1. int a = 5;    // 00000000 00000000 00000000 00000101 
  2. int b = ~a;   // 11111111 11111111 11111111 11111010 (-6) 
要理解为什么二进制数 11111111 11111111 11111111 11111010 表示的数是 -6,需要从补码表示法(Two's Complement)的角度来分析。
因为,有符号整数在计算机中使用补码来表示的。
补码表示法的规则:
1、最高位作为符号位:最高位是 1 时,表示这个数是负数;最高位是 0 时,表示这个数是正数。
2、正数的补码:和原码一样。
3、负数的补码:通过原码的绝对值按位取反后再加 1 得到。
【分析过程】
1、-6 的绝对值是 6,6的原码如下:
  1. 00000000 00000000 00000000 00000110 
2、对原码取反,得到反码,如下:
  1. 11111111 11111111 11111111 11111001 
3、反码加1,得到 -6 的补码(即 -6 的二进制表示):
  1. 11111111 11111111 11111111 11111010 

五、左移 (<<):XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【运算规则】将二进制位向左移动,低位补0。
【示例程序】
  1. // 将 a 的所有二进制位向左移动 1 位 
  2. int a = 5;       // 0101 
  3. int b = a << 1;  // 1010 (10) 
【应用案例】
快速乘以2的幂:n << m 相当于 n * pow(2, m)。
 

六、右移 (>>):XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【运算规则】将二进制位向右移动,高位补0。
【示例程序】
  1. // 将 a 的所有二进制位向右移动 1 位 
  2. int a = 10;     // 1010 
  3. int b = a >> 1;  // 0101 (5) 
  4. int b = a >> 2;  // 0010 (2)(向下取整) 
【应用案例】
快速除以2的幂:n >> m 相当于 n / pow(2, m)。
【注意】
右移操作对于有符号数可能会导致符号扩展问题,需要特别注意。
  1. int a = -8;      // 二进制: 1111...1111000 (32位) 
  2. int b = a >> 1;  // 二进制: 1111...1111100 (-4) 
  3.                  // 左侧补 1 而非补 0 

位运算经典案例XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库
例题-1、统计二进制中1的个数:XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库
 XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. # include <bits/stdc++.h> 
  2. using namespace std; 
  3. int count_1(int n) {    // 统计二进制中 1 的个数 
  4.     int cnt = 0;        // 声明计数变量 cnt 
  5.     while (n) {     // 只要不为 0,持续计数 
  6.         cnt++;      // 每循环一次,计数器加 1 
  7.         n &= (n - 1);   // 去除最低位的 1 
  8.     } 
  9.     return cnt;     // 返回计数结果 
  10. int main() { 
  11.     int n; 
  12.     cin >> n; 
  13.     cout << count_1(n) << endl; 
  14.     return 0; 
手动计算一下,很容易理解统计算法。XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库
例题-2、判断一个正整数是否为2的幂:
  1. # include <bits/stdc++.h> 
  2. using namespace std; 
  3. // 判断一个正整数是否为2的幂 
  4. bool isPowerOfTwo(int n) { 
  5.     return (n > 0) && ((n & (n-1)) == 0); 
  6. int main() { 
  7.     int n; 
  8.     cin >> n; 
  9.     cout << isPowerOfTwo(n) << endl; 
  10.     return 0; 
观察2的幂的二进制表示特征,很容易这么判断的原因。XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库
例题-3、交换两个变量的值:
  1. # include <bits/stdc++.h> 
  2. using namespace std; 
  3. // 交换两个变量的值 
  4. void jiao_huan(int &a, int &b) { 
  5.     a ^= b; 
  6.     b ^= a; 
  7.     a ^= b; 
  8.     return ; 
  9. int main() { 
  10.     int a, b; 
  11.     cin >> a >> b; 
  12.     jiao_huan(a, b);    // 交换a、b的值 
  13.     cout << a << " " << b << endl; 
  14.     return 0; 
在纸上写一写,算一算例题,理解异或运算的交换律和结合律。XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库
例题-4、查找出现奇数次的数字(其余数都出现偶数次):
  1. # include <bits/stdc++.h> 
  2. using namespace std; 
  3. int nums[10]; 
  4. int main() { 
  5.     int n; 
  6.     cin >> n; 
  7.     for (int i = 0; i < n; i++) cin >> nums[i]; 
  8.     int ret = 0;    // ret存储最终结果,默认为0 
  9.     for (int num : nums) {  // 遍历每个数 
  10.         ret ^= num;     // 将遍历到的数与ret执行异或运算 
  11.     } 
  12.     cout << ret << endl;  // 最终ret中的结果就是出现奇数次的数 
  13.     return 0; 

异或运算的交换律和结合律的灵活运用。XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

注意:本案例只适用于仅一个数出现奇数次,其它数都出现偶数次的情况;如果有多个数出现奇数次,无法直接使用该方法。XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

 XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

例题-5、位掩码权限系统:XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库
 XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. const int READ = 1 << 0;   // 0001 
  2. const int WRITE = 1 << 1;  // 0010 
  3. const int EXEC = 1 << 2;   // 0100 
  4. // 设置权限 
  5. int permissions = READ | WRITE; // 0011 
  6. // 检查权限 
  7. bool canRead = permissions & READ; 
  8. bool canExec = permissions & EXEC; 
  9. // 添加权限 
  10. permissions |= EXEC; 
  11. // 移除权限 
  12. permissions &= ~WRITE; 

Linux系统的权限控制就是这么设定的,只不过在此基础上增加以下三种粒度不同的权限控制:文件拥有者 (User)所属组 (Group) 和 其他用户 (Others)。XRq100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

关 键 词

C++

相关教程

提示声明

  • 免责声明:本站资源均来自网络或者用户投稿,仅供用于学习和交流:如有侵权联系删除!

猜你喜欢