【C++指南】位运算知识详解

.
💓 博客主页:倔强的石头的CSDN主页
📝Gitee主页:倔强的石头的gitee主页
⏩ 文章专栏:《C++指南》
期待您的关注

文章目录

  • 引言
    • 一、位运算符概述
        1. 按位与(`&`)
        1. 按位或(`|`)
        1. 按位异或(`^`)
        1. 按位取反(`~`)
        1. 左移(`<<`)
        1. 右移(`>>`)
    • 二、位运算的实战使用技巧
        1. 判断奇偶性
        1. 交换两个数的值
        1. 找出只出现一次的数字
        1. 计算一个数的二进制表示中 `1` 的个数
    • 三、总结

引言

在C++编程中,位运算是一种直接对二进制位进行操作的运算方式。它不仅可以提高程序的运行效率,还能解决一些特定的算法问题,如"只出现一次的数字"系列题目。

下面将详细介绍C++位运算的相关知识,包括位运算符的使用、规则以及实战使用技巧。

一、位运算符概述

C++ 提供了六种位运算符,分别是按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移(<<)和右移(>>)。下面将分别介绍这些运算符的使用和规则。

1. 按位与(&)

  • 规则 :对两个操作数的对应二进制位进行与运算,只有当两个对应位都为 1 时,结果位才为 1,否则为 0。
  • 示例代码:
cpp 复制代码
#include <iostream>
int main() {
    int a = 5; // 二进制表示: 0101
    int b = 3; // 二进制表示: 0011
    int result = a & b; // 二进制结果: 0001,十进制为 1
    std::cout << "a & b = " << result << std::endl;
    return 0;
}
  • 解释 :在上述代码中,a 的二进制表示为 0101,b 的二进制表示为 0011。按位与运算时,逐位进行比较,只有第四位(从右往左数)两个操作数都为 1,所以结果的二进制表示为 0001,十进制为 1。

2. 按位或(|)

  • 规则 :对两个操作数的对应二进制位进行或运算,只要两个对应位中有一个为 1,结果位就为 1,只有当两个对应位都为 0 时,结果位才为 0。
  • 示例代码:
cpp 复制代码
#include <iostream>
int main() {
    int a = 5; // 二进制表示: 0101
    int b = 3; // 二进制表示: 0011
    int result = a | b; // 二进制结果: 0111,十进制为 7
    std::cout << "a | b = " << result << std::endl;
    return 0;
}
  • 解释 :a 的二进制表示为 0101,b 的二进制表示为 0011。按位或运算时,逐位比较,只要有一个位为 1,结果位就为 1,所以结果的二进制表示为 0111,十进制为 7。

3. 按位异或(^)

  • 规则 :对两个操作数的对应二进制位进行异或运算,当两个对应位不同时,结果位为 1,相同时结果位为 0。
  • 示例代码:
cpp 复制代码
#include <iostream>
int main() {
    int a = 5; // 二进制表示: 0101
    int b = 3; // 二进制表示: 0011
    int result = a ^ b; // 二进制结果: 0110,十进制为 6
    std::cout << "a ^ b = " << result << std::endl;
    return 0;
}
  • 解释 :a 的二进制表示为 0101,b 的二进制表示为 0011。按位异或运算时,逐位比较,不同位为 1,相同位为 0,所以结果的二进制表示为 0110,十进制为 6。

4. 按位取反(~)

  • 规则 :对操作数的每一个二进制位进行取反操作,即 1 变为 0,0 变为 1。
  • 示例代码:
cpp 复制代码
#include <iostream>
int main() {
    int a = 5; // 二进制表示: 0101
    int result = ~a; // 二进制结果: 1010(补码表示),十进制取决于具体的编译器和机器
    std::cout << "~a = " << result << std::endl;
    return 0;
}
  • 解释 :a 的二进制表示为 0101,按位取反后为 1010。在计算机中,整数通常以补码形式存储,所以 ~a 的实际十进制值取决于具体的编译器和机器。

5. 左移(<<)

  • 规则 :将操作数的二进制位向左移动指定的位数,右边空出的位用 0 填充。左移 n 位相当于将操作数乘以 2 的 n 次方。
  • 示例代码:
cpp 复制代码
#include <iostream>
int main() {
    int a = 5; // 二进制表示: 0101
    int result = a << 2; // 二进制结果: 010100,十进制为 20
    std::cout << "a << 2 = " << result << std::endl;
    return 0;
}
  • 解释 :a 的二进制表示为 0101,左移 2 位后,右边空出的两位用 0 填充,得到 010100,十进制为 20,相当于 5 * 2^2。

6. 右移(>>)

  • 规则 :将操作数的二进制位向右移动指定的位数。对于无符号数,左边空出的位用 0 填充;对于有符号数,左边空出的位用符号位(正数为 0,负数为 1)填充。右移 n 位相当于将操作数除以 2 的 n 次方。
  • 示例代码:
cpp 复制代码
#include <iostream>
int main() {
    int a = 5; // 二进制表示: 0101
    int result = a >> 1; // 二进制结果: 0010,十进制为 2
    std::cout << "a >> 1 = " << result << std::endl;
    return 0;
}
  • 解释 :a 的二进制表示为 0101,右移 1 位后,左边空出的位用 0 填充,得到 0010,十进制为 2,相当于 5 / 2。

二、位运算的实战使用技巧

1. 判断奇偶性

可以使用按位与运算判断一个整数的奇偶性。如果一个数的二进制表示的最低位为 1,则该数为奇数;如果最低位为 0,则该数为偶数。

cpp 复制代码
#include <iostream>
bool isOdd(int num) {
    return (num & 1) == 1;
}
int main() {
    int num = 5;
    if (isOdd(num)) {
        std::cout << num << " is odd." << std::endl;
    } else {
        std::cout << num << " is even." << std::endl;
    }
    return 0;
}

2. 交换两个数的值

可以使用按位异或运算交换两个数的值,而不需要使用额外的临时变量。

cpp 复制代码
#include <iostream>
void swap(int& a, int& b) {
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}
int main() {
    int a = 5;
    int b = 3;
    std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;
    swap(a, b);
    std::cout << "After swap: a = " << a << ", b = " << b << std::endl;
    return 0;
}

3. 找出只出现一次的数字

在"只出现一次的数字"系列题目中,利用按位异或运算的特性可以高效地找出只出现一次的数字。例如,在一个数组中,除了一个元素只出现一次,其余元素都出现两次,通过对数组中所有元素进行异或运算,最终结果就是只出现一次的元素。

cpp 复制代码
#include <iostream>
#include <vector>
int singleNumber(std::vector<int>& nums) {
    int result = 0;
    for (int num : nums) {
        result ^= num;
    }
    return result;
}
int main() {
    std::vector<int> nums = {1, 2, 2, 3, 3};
    int single = singleNumber(nums);
    std::cout << "The single number is: " << single << std::endl;
    return 0;
}

关于该问题的更多实践可参考文章:
【C++指南】"单身狗问题"------只出现一次的数字 系列问题

4. 计算一个数的二进制表示中 1 的个数

可以使用按位与运算和右移运算来计算一个数的二进制表示中 1 的个数。

cpp 复制代码
#include <iostream>
int countOnes(int num) {
    int count = 0;
    while (num) {
        count += num & 1;
        num >>= 1;
    }
    return count;
}
int main() {
    int num = 5;
    int onesCount = countOnes(num);
    std::cout << "The number of 1s in the binary representation of " << num << " is: " << onesCount << std::endl;
    return 0;
}

三、总结

位运算是 C++ 中一种强大而高效的运算方式,通过对二进制位的直接操作,可以解决许多复杂的问题。

在实际编程中,合理运用位运算符可以提高程序的性能和效率。

需要注意的是,位运算的结果通常依赖于具体的编译器和机器,特别是在处理有符号数的右移操作时,要考虑符号位的影响。

同时,位运算的代码可能会比较难以理解和调试,因此在使用时要谨慎,并添加必要的注释。

相关推荐
我是人✓14 分钟前
Java核心语法:作用域、循环与大数值处理
java·开发语言·后端
敲代码的乔帮主18 分钟前
Python 3 现代类型标注入门
开发语言·python
夜之眷属34 分钟前
PriorityQueue:for-each 遍历和 poll 取出,顺序一样吗?
java·服务器·数据结构·后端·算法
‎ദ്ദിᵔ.˛.ᵔ₎1 小时前
c++11:fuction包装器
开发语言·c++
kimnoic1 小时前
Python 爬虫的原理
开发语言·python
Fluxproxy1 小时前
Python爬虫异步提速终极方案|线程池ThreadPoolExecutor实战,告别单线程慢速爬取
开发语言·爬虫·python
蜗牛互联网1 小时前
Java标准HTTP调用多模态模型的票据抽取前置校验
java·人工智能·python·http
淡海水1 小时前
02-07-原理篇-GC暂停时间的本质
开发语言·unity·c#·gc·暂停时间
工具派1 小时前
Agent 不是玄学:用 Java 状态机思维理解 LangGraph
java·人工智能·python
霍霍的袁1 小时前
【C++】哈希表实现指南:从原理到开放定址法、链地址法的实现
c++·学习·哈希算法·散列表·visual studio