快速读取数据
这段代码是一个快速读取整数的自定义函数,通常用于ACM竞赛或高性能计算场景。它通过getchar()
直接读取字符,比scanf()
和cin
更快,尤其适合处理大规模数据。以下是详细解析:
一、代码功能总览
该函数实现了从标准输入读取一个整数(支持正负),核心逻辑分为两步:
- 跳过非数字字符,识别正负号
- 读取数字字符并转换为整数
二、逐行解析
inline int read() {int x = 0, f = 1; // x存储整数结果,f标记正负(1为正,-1为负)char ch = getchar(); // 读取第一个字符// 第一步:跳过非数字字符,处理正负号while (ch < '0' || ch > '9') { // 当字符不是数字时if (ch == '-') f = -1; // 遇到负号,标记负数ch = getchar(); // 继续读取下一个字符}// 第二步:读取数字字符并转换为整数while (ch >= '0' && ch <= '9') { // 当字符是数字时x = x * 10 + ch - '0'; // 核心转换:字符转数字并累乘ch = getchar(); // 读取下一个字符}return x * f; // 应用正负号,返回最终结果
}
三、核心转换原理
1. 字符转数字
ch - '0'
:将字符(如'5'
)转换为对应的整数(5)。
原理:字符'0'
到'9'
的ASCII码是连续的,'5' - '0' = 5
。
2. 逐位累加
x = x * 10 + digit
:按位构建整数。
例如,读取'1' '2' '3'
时:- 初始
x=0
,读取'1'
→x = 0*10 + 1 = 1
- 读取
'2'
→x = 1*10 + 2 = 12
- 读取
'3'
→x = 12*10 + 3 = 123
- 初始
四、与scanf/cin的性能对比
函数 | 读取1e7个整数的时间(近似) | 优势场景 |
---|---|---|
cin | 约1.5秒 | 简单场景,代码可读性高 |
scanf | 约0.5秒 | 中等数据量 |
read() | 约0.2秒 | 超大数据量(1e6+) |
性能优势原因:
- 跳过了
scanf
的格式解析和cin
的类型安全检查 - 直接操作字符,减少函数调用开销
inline
关键字避免函数调用栈开销
五、示例使用
#include <cstdio>
using namespace std;inline int read() {int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = getchar();}while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}return x * f;
}int main() {int n = read(); // 读取整数nint arr[100000];for (int i = 0; i < n; i++) {arr[i] = read(); // 快速读取数组}return 0;
}
六、注意事项
-
输入合法性
- 若输入非数字字符(如字母),函数会跳过直到遇到数字或EOF。
- 输入
"-123a456"
会被解析为-123
。
-
溢出处理
- 若输入超过
int
范围(如2147483648
),会导致整数溢出,需改用long long
:inline long long read() { /* 同理,返回long long */ }
- 若输入超过
-
配合其他输入函数
- 若之前使用过
cin
或scanf
,需用getchar()
清除缓冲区残留的换行符。
- 若之前使用过
七、扩展:带错误处理的版本
inline bool read(int& x) {x = 0;int f = 1;char ch = getchar();while (ch != EOF && (ch < '0' || ch > '9')) {if (ch == '-') f = -1;ch = getchar();}if (ch == EOF) return false; // 输入结束while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}x *= f;return true;
}// 使用:
int a;
if (read(a)) {// 读取成功
} else {// 输入结束或格式错误
}
这种快速读取方法是ACM竞赛中的常用技巧,能有效解决大数据输入时的超时问题,建议在处理1e5以上数据量时使用。