1698 字
8 分钟
C++ 编程技巧集锦

C++ 编程技巧集锦#

整理日期: 2025-11-04
核心原则: 简洁、高效、实用
适用场景: 算法竞赛、日常开发、代码优化


目录#

  1. 位运算技巧
  2. 字符串处理
  3. 数学计算
  4. 输入输出优化
  5. 常用判断函数

位运算技巧#

1. 判断一个数是否是 2 的幂#

核心原理: 2 的幂在二进制中只有一个 1

bool isPowerOfTwo(int x) {
return x > 0 && (x & (x - 1)) == 0;
}

为什么有效?

  • x = 8 → 二进制 1000
  • x - 1 = 7 → 二进制 0111
  • x & (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 % 2
  • n >>= 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); // 3
ceilDiv(9, 3); // 3
ceilDiv(10, 3); // 4

2. 判断质数#

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
  • ab 中,至少有一个 ≤ √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);
}

规则记忆:

  1. 能被 400 整除 → 闰年(如 2000)
  2. 能被 100 整除但不能被 400 整除 → 平年(如 1900)
  3. 能被 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 40

2. 输出精度控制#

方法 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)) == 0O(1)
统计二进制 1n &= (n-1) 循环O(k)
判断质数检查到 √xO(√n)
判断闰年`year % 400 == 0
向上取整(a + b - 1) / bO(1)

最佳实践建议#

1. 优先使用 STL#

// 不推荐:手写反转
for (int i = 0; i < n/2; i++) {
swap(arr[i], arr[n-1-i]);
}
// 推荐:使用 STL
reverse(arr, arr + n);

2. 位运算代替乘除法#

// 不推荐
n = n / 2;
n = n * 2;
// 推荐
n >>= 1; // 除以 2
n <<= 1; // 乘以 2

3. 避免重复计算#

// 不推荐
for (int i = 2; i <= sqrt(n); i++) { ... }
// 推荐
for (int i = 2; i * i <= n; i++) { ... }

记住这些金句#

“位运算是性能优化的利器,但可读性要适度考虑。” - Linus Torvalds
”好的程序员关心数据结构,而不是代码。” - Linus Torvalds
”简单的算法 + 优秀的数据结构 = 高效的程序。“


继续学习#

这些技巧只是冰山一角。建议:

  1. 实践: 在 LeetCode/Codeforces 上应用这些技巧
  2. 总结: 遇到新技巧及时记录
  3. 理解: 不要死记硬背,理解原理更重要
  4. 对比: 多种方法对比,选择最适合的

记住: 代码是写给人看的,顺便让机器执行。清晰 > 技巧。


文档版本: v1.0
最后更新: 2025-11-04
维护者: WuXie

C++ 编程技巧集锦
https://wuxie233.com/posts/cpp-tricks/
作者
WuXie
发布于
2025-11-04
许可协议
CC BY-NC-SA 4.0