异或与0的关系:二进制世界的身份保持者

一、为什么 a ^ 0 = a?

这是异或运算最直观的性质。让我们从二进制位的角度来理解:

逐位分析

考虑任意一位 a(0 或 1)与 0 的异或:

a0a ^ 0结果等于 a 吗?
000✓ 相同
101✓ 相同

解释

  • 当 a = 0 时:0 ^ 0 = 0 → 结果还是 0
  • 当 a = 1 时:1 ^ 0 = 1 → 结果还是 1

关键观察:0 就像一面镜子,它不改变任何东西的特性。你是什么,经过 0 的异或后,你还是什么。

二、实际例子

例子1:十进制数的异或

5 ^ 0 = 5
二进制:0101 ^ 0000 = 0101

逐位看

  • 第0位:1 ^ 0 = 1
  • 第1位:0 ^ 0 = 0
  • 第2位:1 ^ 0 = 1
  • 第3位:0 ^ 0 = 0

每一位都没有改变!

例子2:负数

-3 ^ 0 = -3

在补码表示中,-3 的二进制是…11111101(假设8位),与 0 异或后,每一位都不变,所以还是 -3。

三、为什么这个性质重要?

1. 初始化

在算法中,0 常常作为计算的起点

int xor_sum = 0;  // 初始化为0
for (int num : nums) {
    xor_sum ^= num;  // 第一次:0 ^ num = num
}

如果没有 a ^ 0 = a 的性质,上面的代码就无法正确工作。

2. 单位元

在数学中,0 是异或运算的单位元(identity element):

  • 单位元:对任意元素 a,有 a ⊕ 0 = a
  • 这是群论中的一个重要概念

3. 可逆运算的基础

异或运算的可逆性依赖于这个性质:

如果 a ^ b = c
那么 a = c ^ b
证明:c ^ b = (a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a

看到最后一步了吗?如果没有 a ^ 0 = a,我们就无法得到 a。

四、与加法的类比

运算单位元性质类比
加法0a + 0 = a加0不改变数值
乘法1a × 1 = a乘1不改变数值
异或0a ^ 0 = a异或0不改变数值

有趣的事实

  • 0 是加法的单位元
  • 0 是异或的单位元
  • 1 是乘法的单位元
  • ∅(空集)是并集的单位元

五、实际应用

应用1:交换两个变量

回顾经典的交换算法:

void swap(int &a, int &b) {
    a = a ^ b;  // 步骤1
    b = a ^ b;  // 步骤2:此时 b = (a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a
    a = a ^ b;  // 步骤3:此时 a = (a ^ b) ^ a = (a ^ a) ^ b = 0 ^ b = b
}

步骤2 和 步骤3 都依赖于 a ^ 0 = a 的性质。

应用2:找唯一数字

int findSingleNumber(vector<int>& nums) {
    int result = 0;
    for (int num : nums) {
        result ^= num;
    }
    return result;
}

为什么这个能工作?

  • 因为 a ^ a = 0(相同的数抵消)
  • 因为 a ^ 0 = a(最后剩下的数不变)

假设数组是 [2, 1, 4, 1, 2]:

初始: 0
0 ^ 2 = 2
2 ^ 1 = 3
3 ^ 4 = 7
7 ^ 1 = 6
6 ^ 2 = 4
结果是4

六、几何解释

想象一个开关控制灯的场景:

  • 灯的状态:开(1)或关(0)
  • 操作:按开关(1)或不按(0)
  • 当前状态 ⊕ 操作 = 新状态

那么:

  • 如果当前状态是 1(灯开着),按开关(1):1 ⊕ 1 = 0(关灯)
  • 如果当前状态是 1(灯开着),不按(0):1 ⊕ 0 = 1(保持开着)

0 操作就是不改变当前状态

七、数学证明

从布尔代数的角度:

异或运算的真值表:

aba ⊕ b
000
011
101
110

当 b = 0 时:

a0a ⊕ 0
000
101

可以看出,结果列与 a 列完全相同。所以 a ⊕ 0 = a。

八、编程中的验证

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    int numbers[] = {0, 1, 5, -3, 12345};
    
    for (int a : numbers) {
        int result = a ^ 0;
        cout << a << " ^ 0 = " << result;
        if (a == result) {
            cout << " ✓ 相等" << endl;
        } else {
            cout << " ✗ 不相等" << endl;
        }
    }
    
    // 二进制展示
    int x = 13;  // 二进制:1101
    cout << "\n13 的二进制: " << bitset<4>(x) << endl;
    cout << "0 的二进制:  " << bitset<4>(0) << endl;
    cout << "13 ^ 0 = " << (x ^ 0) << " (" << bitset<4>(x ^ 0) << ")" << endl;
    
    return 0;
}

输出:

0 ^ 0 = 0 ✓ 相等
1 ^ 0 = 1 ✓ 相等
5 ^ 0 = 5 ✓ 相等
-3 ^ 0 = -3 ✓ 相等
12345 ^ 0 = 12345 ✓ 相等

13 的二进制: 1101
0 的二进制:  0000
13 ^ 0 = 13 (1101)

九、思考题

  1. 为什么 a ^ 0 = a,但 a ^ 1 不一定等于 a?
  2. 如果有 a ^ b = 0,那么 a 和 b 是什么关系?
  3. 在什么情况下 a ^ 0 ≠ a?

总结

a ^ 0 = a​ 是异或运算的基石性质,它意味着:

  • 0 是异或运算的中性元素
  • 任何数与 0 异或,都保持不变
  • 这使 0 成为异或运算的起点复位点

这个简单的性质虽然看起来显而易见,但它是许多复杂算法的基础。就像数学中 0 是加法的单位元一样,在异或的世界里,0 也扮演着类似的角色——不改变任何事物的观察者

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇