1698 字
8 分钟
C++ 编程技巧集锦
C++ 编程技巧集锦
整理日期: 2025-11-04
核心原则: 简洁、高效、实用
适用场景: 算法竞赛、日常开发、代码优化
目录
位运算技巧
1. 判断一个数是否是 2 的幂
核心原理: 2 的幂在二进制中只有一个 1
bool isPowerOfTwo(int x) { return x > 0 && (x & (x - 1)) == 0;}为什么有效?
x = 8→ 二进制1000x - 1 = 7→ 二进制0111x & (x-1) = 0→ 只有 2 的幂满足这个条件
实例:
isPowerOfTwo(8); // true (1000)isPowerOfTwo(16); // true (10000)isPowerOfTwo(15); // false (1111)2. 统计二进制中 1 的个数
方法 1: 逐位判断(普通)
int countOnes(int n) { int count = 0; while (n > 0) { if (n % 2 == 1) count++; n /= 2; } return count;}时间复杂度: O(log n)
方法 2: 位运算(推荐)
int countOnes(int n) { int count = 0; while (n > 0) { if (n & 1) count++; // 检查最低位 n >>= 1; // 右移一位 } return count;}为什么更快?
- 位运算直接操作二进制,比除法和取模快得多
n & 1等价于n % 2n >>= 1等价于n /= 2
方法 3: Brian Kernighan 算法(最优)
int countOnes(int n) { int count = 0; while (n > 0) { n &= (n - 1); // 消除最右边的 1 count++; } return count;}时间复杂度: O(k),k 是 1 的个数
原理:
n & (n-1)会将 n 最右边的 1 变成 0- 例如:
12 (1100) & 11 (1011) = 8 (1000)
字符串处理
1. 字符串反转
方法 1: 手动反转
string reverseManual(string s) { string result(s.size(), ' '); for (int i = 0; i < s.size(); i++) { result[i] = s[s.size() - i - 1]; } return result;}方法 2: STL reverse(推荐)
#include <algorithm>
// 反转整个字符串string s = "hello";reverse(s.begin(), s.end()); // "olleh"
// 反转指定区间 [left, right)reverse(s.begin() + 1, s.begin() + 4); // 反转索引 [1, 4)
// 适用于所有容器vector<int> v = {1, 2, 3, 4, 5};reverse(v.begin(), v.end()); // {5, 4, 3, 2, 1}
int arr[] = {1, 2, 3, 4, 5};reverse(arr, arr + 5); // 数组也可以性能:
- 时间复杂度: O(n)
- 空间复杂度: O(1) - 原地反转
2. 删除字符串的一部分
string s = "hello";
// 删除从位置 pos 开始的所有字符s.erase(1); // "h"
// 从位置 pos 开始删除 len 个字符s = "hello";s.erase(1, 2); // "hlo" (删除 "el")
// 删除后,后续字符自动前移注意事项:
erase()会修改原字符串- 删除后的字符串长度自动调整
- 不会出现”空洞”
数学计算
1. 向上取整(无浮点数)
// 计算 ceil(a / b),但不使用浮点数int ceilDiv(int a, int b) { return (a + b - 1) / b;}原理:
- 正常:
7 / 3 = 2(向下取整) - 向上:
(7 + 3 - 1) / 3 = 9 / 3 = 3
实例:
ceilDiv(7, 3); // 3ceilDiv(9, 3); // 3ceilDiv(10, 3); // 42. 判断质数
bool isPrime(int x) { if (x < 2) return false;
// 只需检查到 √x for (int i = 2; i * i <= x; i++) { if (x % i == 0) return false; } return true;}为什么只检查到 √x?
- 如果 x 有因子
a,必然有对应的b = x/a a和b中,至少有一个 ≤ √x- 所以只需检查 ≤ √x 的因子
优化技巧:
bool isPrime(int x) { if (x < 2) return false; if (x == 2) return true; if (x % 2 == 0) return false; // 排除偶数
// 只检查奇数 for (int i = 3; i * i <= x; i += 2) { if (x % i == 0) return false; } return true;}3. 判断闰年
bool isLeap(int year) { // 能被 400 整除,或者能被 4 整除但不能被 100 整除 return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);}规则记忆:
- 能被 400 整除 → 闰年(如 2000)
- 能被 100 整除但不能被 400 整除 → 平年(如 1900)
- 能被 4 整除但不能被 100 整除 → 闰年(如 2024)
实例:
isLeap(2000); // true (400 的倍数)isLeap(1900); // false (100 的倍数但不是 400 的倍数)isLeap(2024); // true (4 的倍数)isLeap(2023); // false输入输出优化
1. 一行读取多个数字
#include <iostream>#include <sstream>#include <string>using namespace std;
string line;getline(cin, line); // 读取整行
stringstream ss(line);int num;while (ss >> num) { // 逐个处理每个数字 cout << num << " ";}使用场景:
- 输入格式:
1 2 3 4 5 - 数字个数不确定
实例:
// 输入: "10 20 30 40"// 输出: 10 20 30 402. 输出精度控制
方法 1: printf(C 风格)
#include <cstdio>
double v = 14.14285;
printf("%.2f", v); // 14.14 (保留 2 位小数)printf("%.3f", v); // 14.143 (保留 3 位小数)printf("%.1f", v); // 14.1 (保留 1 位小数)方法 2: cout + fixed + setprecision(C++ 风格,推荐)
#include <iostream>#include <iomanip>using namespace std;
double v = 14.14285;
cout << fixed << setprecision(2) << v; // 14.14注意:
fixed表示定点表示法(非科学计数法)setprecision(n)设置小数点后 n 位
3. 避免精度丢失
错误示例
int sum = 8, total = 12;
// 错误!整数除法会丢失精度if (sum * 2 / 3 >= total) { // 8*2/3 = 16/3 = 5 cout << "通过";}正确做法
// 方法 1: 交叉相乘(推荐)if (sum * 2 >= total * 3) { // 16 >= 36? false cout << "通过";}
// 方法 2: 使用浮点数if (sum * 2.0 / 3 >= total) { cout << "通过";}为什么交叉相乘更好?
- 避免浮点数运算
- 避免精度问题
- 性能更好
常用判断函数汇总
快速参考表
| 功能 | 函数实现 | 时间复杂度 |
|---|---|---|
| 判断 2 的幂 | x > 0 && (x & (x-1)) == 0 | O(1) |
| 统计二进制 1 | n &= (n-1) 循环 | O(k) |
| 判断质数 | 检查到 √x | O(√n) |
| 判断闰年 | `year % 400 == 0 | |
| 向上取整 | (a + b - 1) / b | O(1) |
最佳实践建议
1. 优先使用 STL
// 不推荐:手写反转for (int i = 0; i < n/2; i++) { swap(arr[i], arr[n-1-i]);}
// 推荐:使用 STLreverse(arr, arr + n);2. 位运算代替乘除法
// 不推荐n = n / 2;n = n * 2;
// 推荐n >>= 1; // 除以 2n <<= 1; // 乘以 23. 避免重复计算
// 不推荐for (int i = 2; i <= sqrt(n); i++) { ... }
// 推荐for (int i = 2; i * i <= n; i++) { ... }记住这些金句
“位运算是性能优化的利器,但可读性要适度考虑。” - Linus Torvalds
”好的程序员关心数据结构,而不是代码。” - Linus Torvalds
”简单的算法 + 优秀的数据结构 = 高效的程序。“
继续学习
这些技巧只是冰山一角。建议:
- 实践: 在 LeetCode/Codeforces 上应用这些技巧
- 总结: 遇到新技巧及时记录
- 理解: 不要死记硬背,理解原理更重要
- 对比: 多种方法对比,选择最适合的
记住: 代码是写给人看的,顺便让机器执行。清晰 > 技巧。
文档版本: v1.0
最后更新: 2025-11-04
维护者: WuXie