一、🪄✨欢迎来到:C++ 位运算灯泡王国!✨🪄
在计算机世界里,每个数字都不是直接写成“10”、“25”这样的,而是变成一排亮着或灭着的小灯泡。
这些灯泡就是比特位(bit)!
灯泡亮着 =
1灯泡灭着 =
0
比如数字 10 是:
00001010
一排 8 个灯泡,只有两个亮着。
二、🎡位运算,就是操作灯泡的魔法!
你就是灯泡王国的小魔法师。
你有 6 个魔法咒语(运算符),每个咒语都有不同目的:
🧙♂️ 魔法 1:&按位与(“双灯同亮才能亮”魔法)
想象你有两排灯泡牌:
A: 1101
B: 1011
A & B的规则:
👉只有当两个灯都亮着,结果灯才亮。否则灭。
像“双黄灯同时亮才能通行”。
举例:
1101 & 1011 ------ 1001用途:
⭐“过筛子魔法”:把不要的灯泡都筛掉,只保留想要的灯。
🧙♂️ 魔法 2:|按位或(“只要有一个亮就亮”魔法)
这就像“两个人举手,只要一个人举手就算通过”。
1100 | 1010 ------ 1110用途:
⭐ 可以用来“打开某盏灯”。
🧙♂️ 魔法 3:^按位异或(“不一样就亮”魔法)
规则超级简单:
两边一样(都亮或都灭) → 灭
两边不一样 → 亮 ✨
1100 ^ 1010 ------ 0110用途:
⭐ “开关魔法”:切换灯泡状态。
🧙♂️ 魔法 4:~取反(“全部反过来”魔法)
就像魔法棒一扫:
0 → 1
1 → 0
~ 0101 = 1010用途:
⭐ 用来做“反面地图”。
🧙♂️ 魔法 5:<<左移(“向左跑一格”魔法)
就是把灯泡往左推一格,右边补 0。
00000010 << 1 变成: 00000100效果:数字 × 2!就像翻倍魔法。
🧙♂️ 魔法 6:>>右移(“向右跑一格”魔法)
把灯泡往右推。
00001000 >> 1 变成: 00000100效果:数字 ÷ 2!
三、🌟 把灯泡当“超级城市”:位运算更好记!
1、想象一个 8 格的小城市,每格可以住一个小灯泡人:
[7][6][5][4][3][2][1][0]2、城市里的玩法:
🏘️ “打开第 k 个房间的灯”
x |= (1 << k);🏘️ “关掉第 k 个房间的灯”
x &= ~(1 << k);🏘️ “查看第 k 个房间的灯有没有亮”
bool on = (x & (1 << k)) != 0;🏘️ “切换第 k 个灯”
x ^= (1 << k);3、🔥 超生动实例:
(1)让我们从数字 10 开始:
00001010假设我们想打开第 0 个灯(最右边):
使用魔法:
10 | 1 = 00001011灯亮了!✨
如果想关掉第 3 个灯?
11 的二进制 = 00001011 关掉第 3 灯: 00001011 & 11110111 = 00000011int n = 11; // 二进制 00001011 int k = 3; // 第 3 位(从 0 开始) n &= ~(1 << k); // 关掉第 3 位“关掉了第 3 个房间的灯”(房间从0开始)
(2)灯泡村长给你派新任务:
城中8个灯泡按照开关顺序为 00001010,已知最右侧灯泡位置为0,向左分别为1,2,3,4,5,6,7。
要求:“把第 1 号灯打开,把第 3 号灯关闭,把第 2 号灯切换一下。”
代码如下:
int lamp = 0b00001010; // 初始灯泡 lamp |= (1 << 1); // 打开1号灯 lamp &= ~(1 << 3); // 关闭3号灯 lamp ^= (1 << 2); // 切换2号灯执行后灯泡村的灯变成:
00000110四、🎇 小结(附表格)
位运算 =灯泡魔法
| 魔法 | 名字 | 灯泡规则 | 形象比喻 |
|---|---|---|---|
& | 与 | 两个都亮才亮 | 双许可 |
| | 或 | 有一个亮就亮 | 举手投票 |
^ | 异或 | 不一样就亮 | 开关按钮 |
~ | 取反 | 全部反转 | 颠倒魔法 |
<< | 左移 | 向左移动 | ×2 魔法 |
>> | 右移 | 向右移动 | ÷2 魔法 |
五、🕵️♂️《位运算小侦探闯关题》
——用超能力“看见”0/1 小灯泡的世界!
在这些题目里,把整数想象成一排小灯泡:
亮灯 = 1
灭灯 = 0
位运算就是帮我们按灯泡、关灯泡、看灯泡的神奇工具!
🎯 第 1 题
表达式:5 & 1 的结果是多少?
A. 1 B. 4 C. 5 D. 0
解析:
5 = 101(灯泡亮灭亮)
1 = 001(只有最后一个灯亮)
按位与:只有都亮才亮 → 001 =1
👉 答案:A
🎯 第 2 题
表达式:6 | 1 的结果是多少?
A. 6 B. 7 C. 5 D. 4
解析:
6 = 110
1 = 001
按位或:有一个亮就亮 → 111 =7
👉 答案:B
🎯 第 3 题
表达式:4 ^ 1 的结果是多少?
A. 5 B. 3 C. 4 D. 1
解析:
4 = 100
1 = 001
异或:不一样才亮 → 101 =5
👉 答案:A
🎯 第 4 题
表达式:8 >> 1 的结果是多少?
A. 4 B. 16 C. 2 D. 1
解析:
8 = 1000(灯泡向右挪一位)→ 0100 =4
👉 答案:A
🎯 第 5 题
表达式:3 << 2 的结果是多少?
A. 3 B. 6 C. 12 D. 8
解析:
3 = 011
向左搬两次 → 01100 =12
👉 答案:C
🎯 第 6 题
哪个运算能把某一位的“亮灯”关掉?
A. &
B. |
C. ^
D. <<
解析:
关灯=与一个“该位=0”的掩码做 &
👉 答案:A
🎯 第 7 题
哪个运算能把某一位点亮?
A. &
B. |
C. ^
D. >>
解析:
点亮灯=用 1 做 OR
👉 答案:B
🎯 第 8 题
表达式:7 & 2 得多少?
A. 2 B. 7 C. 5 D. 3
解析:
7 = 111
2 = 010
与 → 010 =2
👉 答案:A
🎯 第 9 题
表达式:7 ^ 3 得多少?
A. 5 B. 3 C. 4 D. 7
解析:
7 = 111
3 = 011
异或 → 100 =4
👉 答案:C
🎯 第 10 题
表达式:1 << 4 得多少?
A. 4 B. 16 C. 8 D. 32
解析:
1 左移四格=10000 =16
👉 答案:B
🎯 第 11 题
判断以下表达式结果:
10 & 8 == ?
A. 8 B. 10 C. 2 D. 0
解析:
10 = 1010
8 = 1000
与 → 1000 =8
👉 答案:A
🎯 第 12 题
5 | 2 的结果?
A. 7 B. 6 C. 5 D. 3
解析:
5 = 101
2 = 010
或 → 111 =7
👉 答案:A
🎯 第 13 题
4 ^ 4 的结果?
A. 8 B. 0 C. 4 D. 1
解析:
相同数字异或 → 全灭 →0
👉 答案:B
🎯 第 14 题
1 << 1 的结果?
A. 1 B. 2 C. 3 D. 4
解析:
把唯一的灯泡左挪一格 →2
👉 答案:B
🎯 第 15 题
8 >> 3 的结果?
A. 1 B. 0 C. 8 D. 2
解析:
1000 → 连续右挪三格 → 0001 →1
👉 答案:A
🎯 第 16 题
以下哪项能判断“某位是不是亮着”?
A. a & (1<<k)
B. a | (1<<k)
C. a ^ (1<<k)
D. a>>k
解析:
& 掩码检查某灯是否亮
👉 答案:A
🎯 第 17 题
表达式:12 & 5 的结果?
A. 4 B. 5 C. 0 D. 8
解析:
12 = 1100
5 = 0101
与 → 0100 =4
👉 答案:A
🎯 第 18 题
表达式:12 | 1 的结果?
A. 12 B. 8 C. 13 D. 15
解析:
1100 | 0001 → 1101 =13
👉 答案:C
🎯 第 19 题
表达式:3 ^ 1 = ?
A. 2 B. 3 C. 1 D. 4
解析:
011 ^ 001 → 010 =2
👉 答案:A
🎯 第 20 题
判断: (1 << 3) 的值是多少?
A. 4 B. 3 C. 8 D. 6
解析:
1 左移三格:1000 →8
👉 答案:C
六、课后编程题:
题目 1 — 检查第 k 位是否为 1
题目:
给定一个整数
n(非负)和一个位置k(从 0 开始),判断n的第k位是否为 1。
输入:
两个整数
n k(用空格分开)
输出:
如果第
k位为 1 输出YES,否则输出NO。
示例输入:
13 2(13 的二进制是1101,第 2 位是 1)
示例输出:
YES
思路提示:用掩码(1 << k)与n做按位与:(n & (1 << k)) != 0。
✔ 参考程序:
#include <bits/stdc++.h> using namespace std; int main() { long long n; int k; cin >> n >> k; long long mask = 1LL << k; if ((n & mask) != 0) cout << "YES\n"; else cout << "NO\n"; return 0; }题目 2 — 统计二进制中 1 的个数(popcount)
题目:
给定一个非负整数
n,计算n的二进制表示中有多少个1。
输入:
一个整数n(0 ≤ n ≤ 10^18)
输出:
一个整数 ——
n中 1 的个数。
示例输入:
13(二进制1101,有 3 个 1)
示例输出:
3
思路提示:常用方法:不断用n & 1取最低位然后右移,或用n &= (n-1)每次删除最低的 1(更快)。
✔ 参考程序:
#include <bits/stdc++.h> using namespace std; int main() { long long n; cin >> n; int cnt = 0; while (n) { n &= (n - 1); // 每次清除最低的 1 ++cnt; } cout << cnt << "\n"; return 0; }题目 3 — 找出最低位的 1(返回该位的值及索引)
题目:
给定一个正整数
n(n > 0),找出n最右边(最低)那个为 1 的位,并输出该位的二进制值(即n & -n)和该位的索引(从 0 开始)。
输入:
一个正整数
n
输出:
两个整数,用空格分开:最低 1 的值(十进制),以及最低 1 的索引。
示例输入:
44(二进制00101100)
最低 1 的值是4(00000100),索引是2(从 0 开始)
示例输出:
4 2
思路提示:可从0位开始检查 n & 1 << index,index不断增加,直到找到为止。(题目n>0,不需要考虑找不到的情况)
✔ 参考程序:
#include <bits/stdc++.h> using namespace std; int main() { long long n; cin >> n; int index = 0; long long low = 0; while (n) { if (n & 1) { // 检查最低位是否为 1 low = 1LL << index; // 生成最低位 1 的值 break; } n >>= 1; // 右移一位,检查下一位 ++index; } cout << low << " " << index << "\n"; return 0; }思路提示:low = n & -n可以得到最低位1的值;(需要掌握补码的知识)
✔ 参考程序:
#include <bits/stdc++.h> using namespace std; int main() { long long n; cin >> n; // 假设 n > 0 long long low = n & -n; // 保留最低的 1 int index = 0; long long tmp = low; while (tmp > 1) { tmp >>= 1; ++index; } cout << low << " " << index << "\n"; return 0; }