嵌入式算法——位运算专题

在嵌入式开发中,外设(GPIO、UART、ADC、定时器等)通常通过内存映射的寄存器控制。这些寄存器的每一位或几位代表特定功能(如使能、方向、中断标志等),不用位运算,就无法精确控制某一位而不影响其他位。

例如:从一个 16 位传感器数据中提取高 4 位作为类型,低 12 位作为值:

cpp 复制代码
uint16_t data = read_sensor();
uint8_t type = (data >> 12) & 0x0F;    // 高4位
uint16_t value = data & 0x0FFF;        // 低12位

又或者,设置 GPIOA 的第 5 位为输出高电平

cpp 复制代码
GPIOA->ODR |= (1 << 5);   // 置位:输出高
GPIOA->ODR &= ~(1 << 5);  // 清零:输出低

C/C++ 中常用的位运算符:

运算符 名称 说明 示例(a=5, b=3)
& 按位与 对应位都为1,结果为1 5 & 3 = 1 (0101 & 0011 = 0001)
` ` 按位或 对应位有一个为1,结果为1
^ 按位异或 对应位不同为1 5 ^ 3 = 6 (0101 ^ 0011 = 0110)
~ 按位取反 0变1,1变0 ~5(假设8位)= 11111010 = -6(补码)
<< 左移 各位左移,低位补0 5 << 1 = 10 (0101 → 1010)
>> 右移 逻辑右移(无符号)或算术右移(有符号) 5 >> 1 = 2 (0101 → 0010)

常用位运算技巧

置位(Set bit):reg |= (1 << n); // 将 reg 的第 n 位置 1

清零(Clear bit):reg &= ~(1 << n); // 将 reg 的第 n 位清 0

翻转(Toggle bit):reg ^= (1 << n); // 第 n 位 0→1,1→0

判断某位是否为1:if (reg & (1 << n)) { }

提取连续几位:uint8_t field = (reg >> 2) & 0x07; // 0x07 = 0b111,提取 bits [4:2](共3位)

力扣中对应题目

二进制枚举类问题:78. 子集 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:

    // 位运算,从0000-1111一直遍历所有情况
    vector<vector<int>> subsets(vector<int>& a) {
        vector<vector<int>> result;
        int n = a.size();
        int maxstate = 1 << n;
        for(int s = 0; s < maxstate; s++) {
            vector<int> tmp;
            for(int i = 0; i < n; i++) {
                int b  = (s >> i) & 1;  // 提取s的第i位
                if(b) tmp.push_back(a[i]);
            }
            result.push_back(tmp);
        }
        return result;

    }
};

lowbit类问题:191. 位1的个数 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    // 常规方法
    // int hammingWeight(int n) {
    //     int cnt = 0;
    //     for(int i = 0; i < 32; i++) {
    //         if((n >> i) & 1) cnt++;
    //     }
    //     return cnt;
    // }

    // lowbit 方法
    int hammingWeight(int n) {
        int cnt = 0;
        while(n) {
            int lowbit = n & (-n);
            cnt++;
            n -= lowbit;
        }
        return cnt;
    }
};

数位问题:137. 只出现一次的数字 II - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res = 0;
        for(int i = 0; i < 32; i++) {
            int cnt = 0;
            for(int x : nums) {
                int bit = (x >> i) & 1;
                if(bit) cnt++;
            }
            if(cnt % 3) res |= 1 << i; 
        }

        return res;
    }
};

201. 数字范围按位与 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int rangeBitwiseAnd(int left, int right) {
        int ret = 0;
        for(int i = 30; i >= 0; i--) { // 从最高位开始遍历
            int bl = (left >> i) & 1;  // l的第i位
            int br = (right >> i) & 1;  //  第i位
            if(bl && br) ret |= 1 << i; // 1 1 - res这位也为1
            else if(!bl && br) break; // 0 1 - 这位后面都是0
        }
        return ret;
    }
};

异或技巧类问题:136. 只出现一次的数字 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result = 0;
        for(int i = 0; i < nums.size(); i++){
            result ^= nums[i];
        }
        return result;
    }
};

上面五道题是位运算基础题,也是笔面试常考题,更深入的位运算题目可自行了解。

相关推荐
吃好睡好便好5 小时前
用while循环语句求和
开发语言·学习·算法·matlab·信息可视化
王璐WL5 小时前
【C语言入门级教学】函数的概念2
c语言·数据结构·算法
不知名的忻6 小时前
B 树与 B+ 树:面试完全指南
b树·算法·面试·b+树
运筹vivo@7 小时前
2657. 找到两个数组的前缀公共数组 | 难度:中等
算法·leetcode·职场和发展·哈希表
索木木7 小时前
NCCL SHARP 和 TREE算法
java·服务器·算法
心中有国也有家8 小时前
hccl 架构拆解:昇腾集合通信库到底在做什么?
人工智能·经验分享·笔记·分布式·算法·架构
小O的算法实验室9 小时前
2026年MCS,Q-learning增强MOPSO与改进DWA融合算法+复杂三维地形下特定移动机器人动态路径规划
算法
Peter·Pan爱编程9 小时前
10. new_delete 不是 malloc_free 的包装
c++·人工智能·算法
故事和你9111 小时前
洛谷-【动态规划1】动态规划的引入2
开发语言·数据结构·c++·算法·动态规划·图论
重生之我是Java开发战士11 小时前
【动态规划】背包问题:完全背包,二位费用的背包问题,似包非包
算法·动态规划