欢迎光临
我们一直在努力

Python 位运算实战指南:深入 Python 算法库中的位操作核心技术与经典技巧

Python 位运算实战指南:深入 Python 算法库中的位操作核心技术与经典技巧

【免费下载链接】Python All Algorithms implemented in Python 【免费下载链接】Python 项目地址: https://gitcode.com/GitHub_Trending/pyt/Python

本文以 bit_manipulation 模块为主题,系统讲解位运算(Bit manipulation)的定义、适用场景与 Python 实现方式。位操作是“在计算机最低层级直接操纵比特位”的通用技术——正如模块文档所述,它可用于检测错误(如 Hamming 码)、加密与解密消息(仓库 ciphers 目录有专门实现),也可用于任何需要在最底层处理数据位的场景。读完本文,你将掌握 Python 中六种位运算符的行为差异、单比特读写操作、移位运算与补码原理、popcount/尾零计数等高频技巧,以及格雷码、奇偶位交换等经典算法,并能在面试与工程场景直接套用仓库中的可运行实现。

一、模块定位:bit_manipulation 在仓库中的角色

该仓库是一个用 Python 实现各类算法的合集,bit_manipulation 是其中专注于“比特级操作”的独立模块,目录清单见 bit_manipulation 目录,包含 29 个可独立运行的算法文件,覆盖如下主题:

主题代表文件
基础位运算符(逐位模拟实现) binary_and_operator.py、binary_or_operator.py、binary_xor_operator.py
单比特操作 single_bit_manipulation_operations.py
移位运算 binary_shifts.py
负数补码 binary_twos_complement.py
位计数(popcount、尾零) binary_count_setbits.py、binary_count_trailing_zeros.py、count_number_of_one_bits.py、count_1s_brian_kernighan_method.py
经典位技巧 is_even.py、is_power_of_two.py、power_of_4.py、missing_number.py、find_unique_number.py
编码与序列 gray_code_sequence.py、binary_coded_decimal.py、excess_3_code.py
组合技巧 swap_all_odd_and_even_bits.py、bitwise_addition_recursive.py、reverse_bits.py

模块说明文档见 bit_manipulation/README.md,其中列出了位运算概念与 Python 官方文档中位运算符章节的参考资料,可辅助理解运算符的语义来源。

二、Python 位运算符速览

Python 对整数提供六个内置位运算符:&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移)、>>(右移)。理解这些运算符是后续所有技巧的基础,而仓库的做法正是先“从底层逐位模拟”一遍,帮助读者建立位与位之间的直觉。

2.1 逐位模拟 AND / OR / XOR

以 binary_and_operator.py 为例,函数 binary_and(a, b) 不使用 & 运算符,而是把两个整数转成二进制字符串后逐位计算:

def binary_and(a: int, b: int) -> str:
if a < 0 or b < 0:
raise ValueError("the value of both inputs must be positive")

a_binary = format(a, "b")
b_binary = format(b, "b")
max_len = max(len(a_binary), len(b_binary))

return "0b" + "".join(
str(int(char_a == "1" and char_b == "1"))
for char_a, char_b in zip(a_binary.zfill(max_len), b_binary.zfill(max_len))
)

实现要点:

  • 用 format(a, "b") 得到二进制串,zfill(max_len) 补齐到相同长度,保证高位对齐;
  • char_a == "1" and char_b == "1" 逐位判断 AND 真值表,转成 0/1 字符拼接;
  • 输入校验:负数抛出 ValueError,浮点/字符串输入由后续 format/比较自然触发 TypeError。

文件中的 doctest 覆盖了典型用例,如 binary_and(37, 50) 得到 '0b100000'、binary_and(256, 256) 得到 '0b100000000'。

OR 与 XOR 的实现思路完全同构,区别只在逐位真值表:

  • binary_or_operator.py:int("1" in (char_a, char_b)) —— 两位中任一为 1 即得 1;
  • binary_xor_operator.py:int(char_a != char_b) —— 两位不同得 1。

这套“字符串逐位模拟 + doctest 验证”的写法是本目录的统一风格:每个文件都可作为独立脚本运行其自测用例。

2.2 单比特操作:置位、清位、翻转、读取

工程中最常用的位操作是“只动某一位、不动其他位”。single_bit_manipulation_operations.py 给出了五个标准原语,核心是构造一个“只在目标位置为 1 的掩码” 1 << position:

def set_bit(number: int, position: int) -> int:
return number | (1 << position) # OR 掩码:该位置 1,其余位不受影响

def clear_bit(number: int, position: int) -> int:
return number & ~(1 << position) # AND 反掩码:仅该位置 0

def flip_bit(number: int, position: int) -> int:
return number ^ (1 << position) # XOR 掩码:该位置取反

def is_bit_set(number: int, position: int) -> bool:
return ((number >> position) & 1) == 1 # 右移到最低位后与 1 相与

def get_bit(number: int, position: int) -> int:
return int((number & (1 << position)) != 0) # 直接按位与提取

五种操作的掩码逻辑可归纳为一张表:

操作表达式原理
置 1 number \\| (1 << p) OR 只会把目标位置 1,不改动其他位
清 0 number & ~(1 << p) 反掩码除目标位置外全 1
翻转 number ^ (1 << p) XOR 使目标位取反
提取 (number & (1 << p)) != 0 与结果非零即该位为 1
判位 (number >> p) & 1 右移后只剩最低位有效

以 set_bit(0b1101, 1) 为例:掩码 0b0010,0b1101 | 0b0010 = 0b1111,返回 15;clear_bit(0b10010, 1) 得 0b10000(16)。position 约定从 0(最低位)起算,与 1 << p 的语义一致。

2.3 移位运算:逻辑移位与算术移位

binary_shifts.py 实现了三类移位,并明确区分了逻辑移位与算术右移对负数的不同处理:

  • logical_left_shift(number, shift_amount):在二进制串后追加 shift_amount 个 0,等价于 number << shift_amount,如 logical_left_shift(1983, 4) 返回 '0b111101111110000';
  • logical_right_shift(number, shift_amount):直接截断二进制串尾部,等价于无符号的 >>>;当移位量不小于串长时返回 '0b0';
  • arithmetic_right_shift(number, shift_amount):保留符号位——移位后高位补入原最高位(正数补 0、负数补 1),等价于 Python 的 >>。

其中负数分支值得细看(第 88 至 95 行附近):先把负数转成二进制补码串(bin(abs(number) – (1 << length))[3:]),再前补 "1" 保持符号;随后 binary_number[0] * shift_amount 用最高位填充移出空位。例如 arithmetic_right_shift(-1, 1) 返回 '0b11',arithmetic_right_shift(-1983, 4) 返回 '0b111110000100'——高位全是 1,这正是“算术右移保持负数仍为负”的行为。

三、负数表示:二进制补码

Python 的 int 是任意精度整数,并不像 C 语言那样显式用定长补码存储,但很多位技巧(包括上面的算术右移)都建立在补码模型上。binary_twos_complement.py 给出了负整数到定长补码串的转换:

def twos_complement(number: int) -> str:
if number > 0:
raise ValueError("input must be a negative integer")
binary_number_length = len(bin(number)[3:])
twos_complement_number = bin(abs(number) – (1 << binary_number_length))[3:]

return "0b" + twos_complement_number

核心公式是 |number| – 2^n 再取二进制:例如 -5 取 4 位,5 – 16 = -11,其低 4 位即 1011,故 twos_complement(-5) 返回 '0b1011'。这与“按位取反加一”的补码定义完全一致,可对照 binary_shifts.py 中算术右移的负数分支验证同一套推导。

四、位计数技巧:popcount 与尾零统计

4.1 统计 1 的个数

最简单的实现是 binary_count_setbits.py 中的一行式:

return bin(a).count("1")

对负数抛 ValueError、对浮点抛 TypeError,doctest 还验证了 binary_count_setbits(4294967295) == 32(32 位全 1)。目录下另有两种“更算法化”的写法可供对比:

  • count_number_of_one_bits.py:逐位右移并判断;
  • count_1s_brian_kernighan_method.py:Brian Kernighan 法,利用 n & (n – 1) 每次消除最低位的 1,循环次数恰好等于 1 的个数,时间复杂度与 1 的数量成正比而非位数。

n & (n – 1) 是本模块反复出现的关键恒等式:n – 1 会把 n 最低位的 1 变成 0、其后所有 0 变成 1,因此相与后恰好清除最低有效 1。

4.2 统计尾随零

binary_count_trailing_zeros.py 的实现是一句数学等价式:

return 0 if (a == 0) else int(log2(a & -a))

原理:a & -a(此处 -a 即补码取反加一)提取出 a 最低位的 1,得到一个形如 2^k 的数,其以 2 为底的对数 k 就是尾零个数。例如 a = 16 (0b10000),a & -a = 16,log2(16) = 4。

五、经典位技巧:判断、缺失值与幂次

本目录最有面试价值的一组技巧都遵循同一思路:把数值性质翻译成“位模式”来判定。

5.1 奇偶判断

is_even.py 的实现:

return number & 1 == 0

文件 docstring 解释了依据:偶数的二进制末位恒为 0,奇数恒为 1,因此与 0b1 相与即可区分,无需取模运算。

5.2 是否为 2 的幂

is_power_of_two.py:

def is_power_of_two(number: int) -> bool:
if number < 0:
raise ValueError("number must not be negative")
return number & (number – 1) == 0

文件头注释直接给出了位模式推导:若 n = 0..100..00,则 n – 1 = 0..011..11,两者没有交集,n & (n – 1) 必为 0;反之只要有两个 1 就不成立。doctest 中甚至遍历了 2**0 到 2**9999 全量验证。同类的还有 power_of_4.py、find_previous_power_of_two.py 与 largest_pow_of_two_le_num.py,可对照阅读。

5.3 异或求缺失/唯一值

XOR 满足“自身异或自身为 0、交换律与结合律”,因此是消除成对重复值的首选。missing_number.py 与 find_unique_number.py 即基于该性质:把所有数与期望值域(或成对元素)逐一异或,剩下的就是目标值。这一技巧同样贯穿仓库 ciphers 目录中的异或密码实现(如 xor_cipher.py)。

5.4 格雷码序列

gray_code_sequence.py 实现了 n 位格雷码:序列中相邻两项(含首尾)恰好相差 1 位,是编码与硬件状态机中避免多位同时跳变的经典方案。其构造是递归的反射结构:

seq_len = 1 << bit_count # 2^n
smaller_sequence = gray_code_sequence_string(bit_count – 1)
# 前半段前缀 '0',后半段取反序前缀 '1'
for i in range(seq_len // 2):
sequence.append("0" + smaller_sequence[i])
for i in reversed(range(seq_len // 2)):
sequence.append("1" + smaller_sequence[i])

以 gray_code(3) 为例返回 [0, 1, 3, 2, 6, 7, 5, 4],相邻项二进制表示 000→001→011→010→110→111→101→100,每步仅 1 位变化。

5.5 奇偶位一次交换

swap_all_odd_and_even_bits.py 演示了“掩码 + 移位 + 或合并”的组合拳:

even_bits = num & 0xAAAAAAAA # 32 位内所有偶数位(2,4,6…)掩码
odd_bits = num & 0x55555555 # 32 位内所有奇数位(1,3,5…)掩码
return even_bits >> 1 | odd_bits << 1

0xAAAAAAAA 与 0x55555555 互补,先把两组位分开,各自平移 1 位后互不重叠,用 | 合并即完成整体交换,全程只有常数次位运算。doctest 用 show_bits 打印交换前后的 8 位二进制串,如 5 (00000101) → 10 (00001010),便于直观核对。

六、位运算在仓库其他模块中的延伸

模块 README 明确点出两条应用主线:

  • 错误检测:hashes/hamming_code.py 用位插入的方式构造带校验位的汉明码,属于位操作在编码理论中的直接应用;
  • 加解密:ciphers 目录包含 XOR、Beaufort、Verneam(一次一密)等大量依赖位运算的密码实现,如 ciphers/xor_cipher.py。
  • 从源码结构看,bit_manipulation 提供的是“位级原语”,上述模块在其语义之上组合出具体算法,三者构成“原语 → 编码/密码学应用”的清晰层次。

    七、运行与验证方式

    本目录所有文件都遵循同一运行约定:每个 .py 文件末尾带有

    if __name__ == "__main__":
    import doctest
    doctest.testmod()

    因此可直接在仓库根目录执行自测,例如:

    python bit_manipulation/single_bit_manipulation_operations.py
    python bit_manipulation/gray_code_sequence.py

    doctest 会执行 docstring 中的全部用例(含异常路径,如负数输入触发 ValueError),全部通过则无输出、退出码为 0。同时函数均可被导入复用,例如:

    from bit_manipulation.single_bit_manipulation_operations import set_bit, is_bit_set

    n = set_bit(0, 3) # 8
    print(is_bit_set(n, 3)) # True

    注意各实现类函数(如 binary_and、twos_complement)对输入有明确约束:多数要求非负整数,负数或浮点会按 doctest 约定抛出 ValueError/TypeError,复用前请先阅读对应 docstring 中的异常说明。

    八、小结

    bit_manipulation 模块用 29 个可自测的独立文件,覆盖了位操作的完整知识图谱:

    • 运算符直觉:逐位模拟 AND/OR/XOR 建立真值表概念;
    • 单比特原语:|、& ~、^ 配合 1 << p 掩码完成置位/清位/翻转/读取;
    • 移位与补码:逻辑移位与算术右移的差异、负数补码的推导与生成;
    • 位计数:bin(a).count("1")、Kernighan 法、log2(a & -a) 尾零统计;
    • 经典判定:n & 1 判奇偶、n & (n-1) == 0 判 2 的幂、XOR 消重求缺失值;
    • 进阶应用:格雷码的递归反射构造、0xAAAAAAAA/0x55555555 掩码整体交换奇偶位。

    建议的深入路径是:先读 binary_and_operator.py 等三个运算符文件打底,再按 single_bit_manipulation_operations.py → binary_shifts.py → binary_twos_complement.py 掌握原语与负数模型,最后通过第五节的经典技巧与 gray_code_sequence.py、swap_all_odd_and_even_bits.py 体会多运算符组合的威力,并对照 hashes/hamming_code.py 与 ciphers 目录看位运算在编码和密码学中的真实落点。

    【免费下载链接】Python All Algorithms implemented in Python 【免费下载链接】Python 项目地址: https://gitcode.com/GitHub_Trending/pyt/Python

    创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

    赞(0)
    未经允许不得转载:171主机测评 » Python 位运算实战指南:深入 Python 算法库中的位操作核心技术与经典技巧
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址