CC++ & Algorithm

逻辑运算与位运算

困难12
语言版本:C++
概述:学习“与、或、非”逻辑判断,以及计算机底层对二进制位的操作。

逻辑运算与位运算——让程序更聪明的两种方法

在C++编程中,我们经常需要根据条件做出判断,或者对数字进行快速的底层操作。逻辑运算用来组合多个判断条件(比如“年龄大于12且持有票”),结果只有“真”或“假”。而位运算则直接处理整数在内存中的二进制位,能做更高效的计算(比如左移一位相当于乘以2)。这篇文章会从生活例子出发,帮你彻底搞懂这两种运算的区别与用法。


一、逻辑运算:给条件做“选择题”

逻辑运算就像生活中我们做决定时使用的“与、或、非”规则。C++里主要有三个:

运算符名称含义生活例子
&&逻辑与两个条件都成立才为真要进游乐场:年龄≥12 并且 有票
||逻辑或至少一个条件成立就为真今天可以吃零食:考了满分 或者 妈妈开心
!逻辑非把真变成假,假变成真不是小孩:年龄不小于12

1.1 逻辑与 &&

逻辑与要求所有条件同时为真,结果才为真。比如判断一个学生能否参加数学竞赛,需要年龄≥12数学成绩≥90

int age = 15;            // 年龄
int mathScore = 95;      // 数学成绩
bool canJoin = (age >= 12) && (mathScore >= 90);  // 两个条件都满足才能参加

1.2 逻辑或 ||

逻辑或只要有一个条件为真,结果就为真。比如学校游园会,获得入场资格的条件是:之前获得过奖 或者 今天回答对问题

bool hasPrize = false;        // 之前得过奖吗?
bool answerCorrect = true;    // 今天答对了吗?
bool canEnter = hasPrize || answerCorrect;  // 至少一个成立就能进

1.3 逻辑非 !

逻辑非就是“取反”。比如判断一个数是否不是奇数:

int number = 10;          // 数字
bool isNotOdd = !(number % 2 == 1);  // 不是奇数(即偶数)
cout << isNotOdd << endl; // 输出1(true)

1.4 逻辑运算的短路特性

逻辑运算有个有趣的特点:一旦结果确定,后面的条件就不再执行。比如:

int x = 0;
bool result = (x != 0) && (10 / x > 1);  // 第一个条件为假,第二个条件(除零)根本不执行

这个特性在编程中能避免一些错误,比如除零或数组越界。


二、位运算:直接操作二进制位

位运算是对整数在内存里的二进制位进行操作的,比逻辑运算更底层、更高效。常用位运算符有:

运算符名称含义例子(a=5=0101, b=3=0011)
&按位与对应位都为1才为1a & b → 0001 = 1
|按位或对应位至少一个为1就为1a | b → 0111 = 7
^按位异或对应位不同则为1,相同则为0a ^ b → 0110 = 6
<<左移所有位向左移动,右边补0a << 1 → 1010 = 10
>>右移所有位向右移动,左边补0(无符号数)a >> 1 → 0010 = 2

2.1 按位与 & —— 用“与”判断某一位是否为1

比如判断一个数字是奇数还是偶数:奇数的最低位一定是1。通过 num & 1 可以快速判断。

int num = 7;              // 二进制 0111
bool isOdd = (num & 1) == 1;  // 最低位是1 → 奇数

生活中,可以想象每个同学有一张“特权卡”,卡上的每一位代表一种权限(比如第0位:可进入图书馆,第1位:可借书)。用按位与就能检验是否有某个权限。

2.2 按位或 | —— 用来“打开”某一位

想要给一个状态加上某个权限,就用按位或置1。比如初始权限为0(二进制00),加上可进入图书馆(第0位):

int permissions = 0;          // 初始无权限
permissions = permissions | 1; // 打开第0位(二进制01)

2.3 按位异或 ^ —— 翻转一位

异或的特点是:与1异或就翻转,与0异或保持不变。常用于加密、交换两个数(不用临时变量)等。

int a = 5, b = 3;
a = a ^ b;  // a = 5^3 = 6
b = a ^ b;  // b = 6^3 = 5(恢复为原来的a)
a = a ^ b;  // a = 6^5 = 3(恢复为原来的b)
// 现在 a=3, b=5,交换成功

2.4 左移 << 和右移 >> —— 快速乘除2

左移一位相当于乘以2,右移一位相当于除以2(注意:整数向下取整)。这在竞赛中比乘法除法快得多。

int money = 10;              // 零花钱10元
int doubleMoney = money << 1; // 左移一位 = 20元
int halfMoney = money >> 1;   // 右移一位 = 5元

注意:右移时,如果是有符号负数,不同编译器处理方式不同(可能是算术右移保留符号),建议只对无符号整数或非负整数使用。


三、新手最容易犯的错误:混淆逻辑运算与位运算

许多同学刚学时会把 &&& 搞混,把 ||| 搞混。记住关键区别:

  • 逻辑运算两边是布尔表达式(或能转成布尔值的东西),结果只有 truefalse
  • 位运算两边是整数,结果也是整数。

看这个对比:

int a = 2, b = 4;
bool logicAnd = (a > 0) && (b > 0);  // true && true → true
int bitwiseAnd = a & b;              // 0010 & 0100 → 0000 → 0

如果错误地把位运算用在条件判断里,可能得到和预期完全不同的结果。例如 if (a & b) 相当于判断 (a & b) != 0,而不是“两个数都非零时条件为真”。有些竞赛题会利用这一点来设陷阱。


四、完整可运行示例

下面是一个混合使用逻辑运算和位运算的完整程序,你可以直接复制到编译器里跑一跑。

#include <iostream>
using namespace std;

int main() {
    // —— 逻辑运算示例 ——
    int age = 14;                 // 年龄
    bool hasID = true;           // 有身份证吗?
    // 判断能否进入网吧(年龄≥18且带身份证)
    bool canEnterNetbar = (age >= 18) && hasID;
    cout << "能否进网吧? " << (canEnterNetbar ? "可以" : "不行") << endl;
    
    // 判断是否免票(年龄<12 或者 持VIP卡)
    bool hasVIP = false;         // 有VIP卡吗?
    bool isFree = (age < 12) || hasVIP;
    cout << "是否免票? " << (isFree ? "是" : "否") << endl;
    
    // —— 位运算示例 ——
    int score = 92;              // 考试成绩
    // 快速判断成绩是否为偶数(最低位为0)
    bool even = (score & 1) == 0;
    cout << "成绩是否偶数? " << (even ? "是" : "否") << endl;
    
    // 用左移实现分数翻倍(乘以2)
    int doubleScore = score << 1;
    cout << "成绩翻倍(左移1位): " << doubleScore << endl;
    
    // 设置某个权限位(比如第2位表示“可管理”)
    int permission = 0;          // 初始无权限
    permission = permission | 4; // 二进制 100,即第2位置1
    cout << "权限值: " << permission << endl;
    
    // 检查是否有第2位权限
    bool hasAdmin = (permission & 4) != 0;
    cout << "是否有管理权限? " << (hasAdmin ? "有" : "无") << endl;
    
    return 0;
}

运行结果:

能否进网吧? 不行
是否免票? 否
成绩是否偶数? 是
成绩翻倍(左移1位): 184
权限值: 4
是否有管理权限? 有

五、相关知识点指引

  • 条件语句(if / else):逻辑运算经常用在 if 的条件中,比如 if (age >= 12 && hasTicket)
  • 二进制基础:要搞懂位运算,需要先理解二进制、字节、位的概念。
  • 循环中的位运算:可以用位运算快速判断循环的次数是否为2的幂,或者用右移来遍历二进制位。
  • 位运算与枚举(bitmask):竞赛中常用位运算来表示多个布尔状态的组合,比如一个 int 的每一位代表一个选项是否被选中。

逻辑运算和位运算是C++中非常强大的工具,学好了能让你的代码既简洁又高效。多写多练,慢慢就会熟悉啦!

例题精讲

1单选题

在C++中,表达式 (5 > 3) && (2 < 1) 的结果是什么?A. true B. false C. 1 D. 0

Atrue
Bfalse
C1
D0
2判断题

在C++中,对于整数变量a=6,b=3,表达式 ~a 的结果是 -7。

3填空题
以下C++代码用于判断整数 x 的第3位(从0开始编号)是否为1,请填空。int x = 13; // 二进制 1101bool bit3 = (x ___ (1 << 3)) != 0;
4单选题

关于异或运算(^),以下哪个说法是正确的?A. a ^ a 的结果总是1 B. a ^ 0 的结果是a C. a ^ b = a + b D. a ^ b 与 b ^ a 的结果不一定相同

Aa ^ a 的结果总是1
Ba ^ 0 的结果是a
Ca ^ b = a + b
Da ^ b 与 b ^ a 的结果不一定相同
5填空题
以下代码使用位运算将整数 a 的第3位(从0开始)设置为1,其他位保持不变,请填空。int a = 8; // 二进制 1000a = a ___ (1 << 3);