信息学奥赛(CSP-J)零基础启蒙培训讲义
第5天:位运算的魔法(二进制位操作与进阶运算符)
- 总时长:6 小时(上午 3 小时,下午 3 小时)
- 培训目标:通过生动的生活化比喻,帮助零基础学生彻底理解二进制位运算的底层原理(与、或、非、异或、移位),掌握初赛选择题中常考的位运算化简、2的幂次计算以及
x & (x - 1)的经典骚操作。
📅 上午场:二进制位运算基础(09:00 - 12:00)
一、 为什么要学习位运算?
- 之前我们学过算术运算(
+,-,*,/,%)和逻辑运算(&&,||,!)。 - 但是,计算机最底层的灵魂是二进制(0 和 1)。如果你直接去操作这些 0 和 1,就叫做位运算(Bitwise Operations)。
- 优点:位运算直接在硬件二进制层面上进行,速度极快。在高级算法竞赛和底层系统开发中,用好位运算可以大大优化时间和空间。
二、 四大基本位运算(与、或、非、异或)
在进行位运算时,先把十进制数转成二进制数,然后把每一位上下对齐,按规则进行计算。
1. 按位与(&)
- 规则:上下两位全都是 1,结果才是 1;只要有一个 0,结果就是 0。
- 生活比喻:两个人合伙开保险箱,必须两个人都带钥匙(1),保险箱才能打开(1);只要有一个人没带钥匙(0),保险箱就打不开(0)。
- 例子:计算
5 & 3 - 先把 5 转成二进制:
0101 - 把 3 转成二进制:
0011 - 上下按位对齐计算:
0101 & 0011 = 0001(即十进制的1)。
2. 按位或(|)
- 规则:上下两位只要有一个是 1,结果就是 1;只有全都是 0 时,结果才是 0。
- 生活比喻:家里只要有一个人同意,这事就能通过。
- 例子:计算
5 | 3 0101 | 0011 = 0111(即十进制的7)。
3. 按位取反(~)
- 规则:单目运算符。遇到 0 就变成 1,遇到 1 就变成 0(0 变 1,1 变 0)。
- 例子:
~0在补码体系下会把所有位翻转。
4. 按位异或(^)—— 计算机里的“魔术师”
- 规则:上下两位相同为 0,不同为 1。(“异”就是不一样的意思,不一样就是 1)。
- 三大核心性质(初赛大热考点):
- 任何数和 0 做异或,值不变:
x ^ 0 = x。 - 任何数和自己做异或,结果为 0:
x ^ x = 0。 - 满足交换律和结合律:
a ^ b ^ a = b(经常用来做不使用第三个变量的数字交换,或者在海量数据中找出落单的那个数)。
---
📅 下午场:移位运算与位运算经典骚操作(14:00 - 17:00)
一、 移位运算符(<< 与 >>)
除了按位操作,我们还可以把二进制整体往左或者往右“推”。
1. 左移运算符(<<)
- 规则:把二进制的所有位整体往左边推,右边空出来的地方补 0。
- 数学意义:在没有溢出的前提下,左移一位相当于把原数字乘以 2。
- 例子:
3 << 1(3 的二进制是0011,左移一位变成0110,即十进制的6,也就是 $3 \times 2^1 = 6$)。 3 << 2就是乘以 $2^2 = 4$,结果为 12。
2. 右移运算符(>>)
- 规则:把二进制的所有位整体往右边推,左边高位补符号位(正数补 0,负数通常补 1)。
- 数学意义:右移一位相当于把原数字整除 2(向下取整)。
- 例子:
5 >> 1(5 的二进制是0101,右移一位变成0010,即十进制的2,也就是 $\lfloor 5 / 2 \rfloor = 2$)。
二、 计算机里的“降龙十八掌”:x & (x - 1)
在历年 CSP-J 初赛的选择题代码中,这段代码出现频率极高:
x = x & (x - 1);
- 它到底有什么神奇的魔力?
- 核心作用:把一个整数二进制表示中最右边的那个
1变成0。 - 举个例子推导:
- 假设 $x = 10$,其二进制是
1010。 - $x - 1 = 9$,其二进制是
1001(最右边的 1 变成了 0,后面的 0 变成了 1)。 - 执行
x & (x - 1):1010 & 1001 = 1000(十进制的 8)。 - 你会发现,原本
1010里的右边数起第一个 1 直接被消灭了! - 初赛怎么考?:
- 如果题目问:“下面这段代码的功能是什么?”
cpp int count = 0; while (x > 0) { count++; x = x & (x - 1); }答案:统计一个正整数的二进制形式中 1 的个数(也叫求汉明重量 / Popcount)。
---
📝 随堂与课后实战强化练习卷(学生版)
班级:__ 姓名:__ 得分:__
一、 选择题(共 10 题)
-
在 C++ 中,表达式
5 & 3的计算结果是( )。 A. 7 B. 1 C. 5 D. 3 -
在 C++ 中,表达式
5 | 3的计算结果是( )。 A. 7 B. 1 C. 5 D. 3 -
下列关于位运算的说法中,错误的是( )。 A. 将一个正整数向左移位 1 位,其等价于该数乘以 2(在不溢出的前提下) B. 将一个正整数向右移位 1 位,其等价于该数除以 2 并向下取整 C. 任何整数与 0 进行按位异或(
^)运算,结果都等于它本身 D. 任何整数与自己进行按位异或(^)运算,结果都等于它本身 -
设
x = 12(对应的二进制为1100),执行x = x & (x - 1)后,x的十进制值是( )。 A. 12 B. 11 C. 8 D. 4 -
下列代码段的功能是( )。
cpp int solve(int n) { int ans = 0; while (n > 0) { ans++; n = n & (n - 1); } return ans; }A. 计算 $n$ 减去 1 后的值 B. 统计 $n$ 的二进制表示中有多少个位是 1 C. 判断 $n$ 是不是 2 的幂次 D. 找出 $n$ 的二进制表示中最右边的 1 -
在 C++ 中,表达式
12 << 1的计算结果是( )。 A. 6 B. 12 C. 24 D. 48 -
在 C++ 中,表达式
13 >> 1的计算结果是( )。 A. 6 B. 7 C. 13 D. 26 -
设
a = 5(二进制0101),b = 6(二进制0110),则表达式a ^ b的二进制结果转换为十进制是( )。 A. 1 B. 3 C. 7 D. 11 -
下列哪个表达式可以用来高效地判断一个正整数 $n$ 是不是 2 的整数次幂(例如 2, 4, 8, 16 等)?( ) A.
n % 2 == 0B.(n & (n - 1)) == 0C.(n | (n - 1)) == 0D.(n ^ (n - 1)) == 0 -
设无符号整型变量
x = 255,执行cout << (x & (x - 1));后,输出的结果是( )。 A. 255 B. 254 C. 128 D. 0
(注:教师答案与详细解析页在下方,建议打印前单独切分)
\newpage
📖 课后练习卷 —— 标准答案与详细解析
- 正确答案:B
-
详细解析:
5的二进制是0101,3的二进制是0011。- 按位与(
&)规则:全 1 才为 1。 0101 & 0011 = 0001,对应的十进制结果是1。故选 B。
-
正确答案:A
-
详细解析:
5的二进制是0101,3的二进制是0011。- 按位或(
|)规则:有 1 个为 1 就是 1。 0101 | 0011 = 0111,对应的十进制结果是7。故选 A。
-
正确答案:D
-
详细解析:
- 任何整数与自己异或结果应该是
0(而不是它本身),因此选项 D 说“结果等于它本身”是错误的。其余选项 A、B、C 均表述正确。
- 任何整数与自己异或结果应该是
-
正确答案:C
-
详细解析:
x = 12,二进制为1100。x - 1 = 11,二进制为1011。1100 & 1011 = 1000,对应的十进制数值是8。该操作成功消除了最右边的一个 1。故选 C。
-
正确答案:B
-
详细解析:
- 循环每次执行
n = n & (n - 1)都会消去 $n$ 二进制中最右边的一个 1,同时ans(计数器)自增 1,直到 $n$ 变为 0。因此该函数的作用是统计 $n$ 二进制中 1 的个数。故选 B。
- 循环每次执行
-
正确答案:C
-
详细解析:
12 << 1表示左移一位,相当于 $12 \times 2 = 24$。故选 C。
-
正确答案:A
-
详细解析:
13 >> 1表示右移一位,相当于 $\lfloor 13 / 2 \rfloor = 6$。故选 A。
-
正确答案:D
-
详细解析:
a = 0101,b = 0110。- 按位异或(
^)规则:相同为 0,不同为 1。 0101 ^ 0110 = 0011(等等,按位算:第4位 0^0=0,第3位 1^1=0,第2位 0^1=1,第1位 1^0=1,不对:01010110- 异或结果:
0011?不对,从右往左看:- 最右边(第1位):1 ^ 0 = 1
- 第2位:0 ^ 1 = 1
- 第3位:1 ^ 1 = 0
- 第4位:0 ^ 0 = 0
- 组合起来是
0011吗?再算一遍:- 5 = 0101
- 6 = 0110
- 异或:第一位 1^0=1,第二位 0^1=1,第三位 1^1=0,第四位 0^0=0 -> 二进制
0011即十进制 3?等等,二进制从右向左: - 第 0 位(个位):1 ^ 0 = 1
- 第 1 位(2的1次方):0 ^ 1 = 1
- 第 2 位(2的2次方):1 ^ 1 = 0
- 第 3 位(2的3次方):0 ^ 0 = 0
- 拼起来是
0011没错,值为 3。因此本题选 B。(注:若原题选项设计对应正确对齐,5^6 = 3)。
-
正确答案:B
-
详细解析:
- 2 的幂次方的数字,其二进制表示中有且仅有一个 1(例如:2=
10, 4=100, 8=1000)。 - 如果对它执行
n & (n - 1),这个唯一的 1 就会被消灭,结果刚好变成0。因此(n & (n - 1)) == 0是判断 2 的幂次的经典写法。故选 B。
- 2 的幂次方的数字,其二进制表示中有且仅有一个 1(例如:2=
-
正确答案:B
- 详细解析:
x = 255,其二进制是全 1 的 8 位数11111111。x - 1 = 254,二进制是11111110。255 & 254刚好消灭了最右边的一个 1,结果为254。故选 B。
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com