异或 XOR 运算是什么?为什么对于大多数人,不重要?

分类: 365bet体育网址 时间: 2026-07-02 05:32:02 作者: admin 阅读: 8941
异或 XOR 运算是什么?为什么对于大多数人,不重要?

目录1.异或 XOR 的基本概念2.实现一个加密解密器3.不引入三方变量,交换两个变量的值4.算法题,寻找重复的元素5.大名鼎鼎的异或链表

看看它的用法就知道了,没有一个普通人业务里能用到的。所谓有用,只有在 力扣 里刷题很有用,还有面试造飞机时哈哈。

⚠️ 本文完整版全文原文:https://www.ccgxk.com/emlog_dev/626.html

其实软件发展到今天, 能正常工作是第一位,不能正常工作的软件,根本没意义, 可读性和可维护性是第二位,性能是第三位, 不要过早优化, 当性能真正成为瓶颈的时候,才介入优化。---《高效编程的奥秘》

(当然,不是真实项目里完全没有,而是在偏业务的项目里作用基本等于 0,偏底层的则多一点,比如校验、纠错、加密算法,毕竟可逆嘛,但可维护性都会很差)

1.异或 XOR 的基本概念

首先第一个,某个内容 两次 异或 同一个数或内容,它会还原。

比如 Python 里:

>>> 23^12

27

>>> 23^12^12

23

这个特性,很适合让它作为一个加密解密器!

2.实现一个加密解密器

比如这样一个函数:

def xor_encrypt(message: str, key: int) -> str:

result = []

for ch in message:

encrypted_char = chr(ord(ch) ^ key) # 每个字符都和秘钥进行一次 XOR 运算

result.append(encrypted_char)

return ''.join(result) # 最后拼接

那么,你就得到了一个最简单的加密器。

你有一个字符串 'aabbcc',你可以这样加密和解密。

password = 'aabbcc'

key = 67 # 秘钥

encypt = xor_encrypt(password, key)

print('加密后的结果:' + encypt)

print('解密后:' + xor_encrypt(encypt, key))

-----

加密后的结果:""!!

解密后:aabbcc

当然,在真正的密码学里,这种方式,充其量只算做混淆。很容易被破解造成攻击(比如频率分析),生产环境里不能这样使用。

(比如这个反面教材:网易云的缓存加密mp3文件给每一位进行 key= 163 的异或操作就可以还原出原来的文件,嘿嘿~ 当然,这个只防君子不防小人,又不影响他们赚钱.....)

但是,它依然算得上非常原始的加密算法。

3.不引入三方变量,交换两个变量的值

它的另一个巧妙用法是,能让我们不使用任何中间变量来交换两个变量的值!

如果只考虑整数,我们有三种经典方式,其中就包含异或,我们使用 JS 来写:

function swap(a, b) { // 中间变量

let tmp = a;

a = b;

b = tmp;

return [a, b];

}

function swap(a, b) { // 加减法(只对整数起效)

a = a + b;

b = a - b;

a = a - b;

return [a, b];

}

function swap(a, b) { // 我们今天的 XOR 异或了!

if (a === b) return [a, b];

a ^= b;

b ^= a;

a ^= b;

return [a, b];

}

毕竟在多数编程语言里,小数等特殊数值,都有精度丢失问题,第二种不适用,所以 异或 才是真正意义上的不引入第三方变量就能交换 A B 两个位置的数值的方法。

4.算法题,寻找重复的元素

还有,就是寻找重复元素。

这里运用的特性是,0 与任何数字异或都等于它本身。比如在 Python 里:

>>> 0^3

3

>>>0^2

2

>>>8^0

8

>>>0^8^8

0

如果我们有这样一个数组,[0, 1, 2, 3, 4, 5] 。

然后我们找一个数字,将其重复两遍。比如 [0, 1, 2, 2, 3, 4, 5]。

然后我们再打乱这个数组, [4, 2, 3, 1, 5, 2, 0] 。

请问,怎么能最快速的找到那个多出的重复数字是什么?那就要用到异或了!

很脑洞大开是不是,下面是使用 JavaScript 写的一个函数:

function findDuplicate(nums) {

let x = 0

const n = nums.length - 1 // 获取数组的长度

for (let i = 0; i <= n; i++) { // 第一次 XOR 异或

x ^= i

}

for (const v of nums) { // 第二次 XOR 异或

x ^= v

}

return x

}

时间 O(n),空间 O(1),没有排序,没有 Map,没有额外结构,非常优雅。

原理很简单。

第一次异或:

0^0^1^2^3^4^5

第二次异或(等同于):

0^0^1^2^3^4^5^0^1^2^3^4^5^2

没错,多出了一个最后那个 2,前面的都被两次异或了,已经都是 0 了,因此剩下的那个 2 就留下了。

这个特性,在现实的应用场景里,可以用于检测一组数据流,是否多发和少发,速度飞快!以及在储存内容时,快速发现有没有多写或少写一个数据块儿。

5.大名鼎鼎的异或链表

然后下面要讲的就是大名鼎鼎的异或链表了!

传统的链表,一般是双向链表,就像博客里看文章一样,每个节点里,存储着【上一篇】和【下一篇】的链接(指针)。

而异或链表,它不存储 2 个地址了,而是存储一个地址,就是【上一篇】和【下一篇】的两个地址(指针)的 XOR 异或。

这样,好处是:单纯在链表这个结构上,内存占用立马减少了一半。

但是,我们怎么遍历这个链表呢?

首先因为 0^x = x 嘛,所以 头 和 尾,储存的都是 0 和相临地址的异或,也就没有头和尾这个概念了。

由于很难区分头尾和其他节点在地址里的区别,因此我们会给出头和尾,然后你就根据这个异或的特性,就能马上一步步算出后续节点的地址.... 你找到头和尾了,你就能一下子算出来下一个了,直到走完。

但是,它并不实用。

可维护型超级差,中间坏一个节点,全局报废,不可维修!

内存从古至今就是很廉价的东西,没必要为了节省 50% 的地址储存大小,把整个可维护性、可读性完全抛弃。不过确实很有意思吧,是那些算法题里的一个考验大脑的工具。

相关文章

对联知识讲座:怎样写贺联
Aswy悬浮音响(Aswy悬浮音响带你进入音乐的未来)
66手游平台怎么样,66手游平台深度评测,位置解析与使用指南(附2023最新数据)
大金/DAIKIN品牌涉及行业