💡 Code_Tricks
一、0x3f
0x3f在算法题/竞赛代码里早已不是 “63” 这么简单,它被当成一种 “ 安全、易写、不易溢出 ” 的 伪无穷大 使用。
1). 单字节
0x3f--memset的 “填充无穷大”memset按字节赋值。0x3f二进制0011 1111,最高位是 0 → 看成有符号数也是正数。把整型数组每个字节都灌成
0x3f,效果:
| 类型 | 内存示意(四字节) | 十进制值 | 特点 |
|---|---|---|---|
int | 0x3F3F3F3F | 1061109567 | 够大,但不到 INT_MAX , 加法不溢出 |
- 使用示例:
c++
int g[N][N];
memset(g, 0x3f, sizeof g); // 整型“无穷大”矩阵初始化 (如存图的邻接矩阵)- 2). 四字节
0x3f3f3f3f-- 真正“INF”常数- 值 ≈
1.06 × 10^9,远小于INT_MAX(≈2.14 × 10^9)。 - 两个
INF相加:1.06 G + 1.06 G = 2.12 G<INT_MAX,不会溢出。 - 位运算友好:低 6 位全 1,取模、掩码时常能直接用。
- 值 ≈
- 使用示例:
c++
const int INF = 0x3f3f3f3f;
int dist[N];
fill(dist, dist + N, INF);c++
if (dist[u] == INF) // u 还没被松弛c++
if (dist[u] > INF / 2) // 有负权边松弛,但起点不可达二、getline
- 注 :有两个重载版本:
std::getline和istream::getline, 下面讲的是std::getline
- 函数原型:
c++
istream& getline(istream& is, string& str, char delim = '\n');- 读到
delim为止(默认换行符),不把delim放进str - 返回流引用,可直接当 bool 用
- 会丢弃行尾的分隔符(与 C 的
fgets不同)
- 1). 基本用法:
c++
string line;
getline(cin, line); // 读一整行,含空格2). 去除行末换行:
如输入数据:
txt
2
5 6 8 11 9
10 12 9c++
int cnt;
cin >> cnt; // 读到第一行的 2
string line;
getline(cin, line); // 忽略掉第一行的回车
while( cnt -- ){
// 读取正确数据
getline(cin, line);
// .....
}- 3). 循环读文件直到
EOF
c++
ifstream fin("data.txt");
string line;
while (getline(fin, line)) { /* 处理 line */ }三、sstream
- 头文件:
c++
#include <sstream>- 核心类就三个:
istringstream—— 把字符串当成输入流(解析用)ostringstream—— 把字符串当成输出流(拼接用)stringstream—— 既可读又可写(功能最全)
- 1). 字符串 → 多字段解析(
istringstream)
c++
string line = "Tom 18 3.7";
istringstream iss(line);
string name; int age; double gpa;
iss >> name >> age >> gpa; // 按 空格/TAB/换行 分割
if (iss) { /* 解析成功 */ }- 整行读取到末尾时最爽:
c++
while (getline(cin, line)) {
istringstream iss(line);
/* 逐行解析 */
}- 2). 任意类型 → 字符串(
ostringstream)
c++
int id = 7;
double score = 95.5;
ostringstream oss;
oss << "id=" << id << ",score=" << score;
string s = oss.str(); // "id=7,score=95.5"- 3). 字符串 ↔ 任意类型双向(
stringstream)
c++
stringstream ssin;
ssin << 123 << ' ' << 3.14;
int a; double b;
ssin >> a >> b; // 123 3.14四、常用取数
- 1). 某一个十进制数,每次取出最低位:
c++
while(x){
// 把 x 的每一个数取出来
int t = x % 10; // 最低位那个数
x /= 10; // 删掉最低位
// ...其它操作
}- 2). 某一个十进制数对应的二进制表示的每一位:
c++
int x = 11; // 二进制: 1011
while(x){
int t = x & 1; // 取最低位
x >>= 1; // 删掉最低位
cout << t << ' '; // 1 1 0 1
}- 3). 某一个十进制的二进制表示中的第
k位:
c++
n >> k & 1- 4). 某个十进制数的二进制表示的最后一位
1及其后面的0对应是十进制数:
c++
int lowbit(int x){
return x & -x;
}- 5). 一个大长度的十进制数取某个区间技巧:(日期问题中常用)
/ 1000: 取前三位 (这个几位其实就是对应1后面0的个数)% 1000: 取后三位 (这个几位其实就是对应1后面0的个数)
c++
int date = 20251024;
// 取出年月日
int year = date / 10000; // 取前四位
int month = date % 10000 / 100; // 先后四位再取前两位
int day = date % 100; // 取后两位- 对于得到了由秒数来表示的时间,常用转换如下(虽然没上面那样可以数
0的个数那么好记):
c++
int time = get_time(); // time 是获取到了一个由秒数来表示的时间
int hour = time / 3600;
int minute = time % 3600 / 60;
int second = time % 60;五、sscanf
sscanf是 C 语言中的一个标准库函数,用于从字符串中读取格式化输入。它的功能与
scanf类似,但scanf是从标准输入读取,而sscanf是从字符串中读取。
- 函数原型:
c++
int sscanf(const char *str, const char *format, ...);| 参数 | 说明 |
|---|---|
str | 要解析的字符串 |
format | 格式控制字符串(与 printf/scanf 的格式类似) |
... | 指向变量的指针,用于存储解析出来的数据 |
- 返回值:
- 成功时:返回成功赋值的变量个数。
- 失败时:返回
0或负数(通常是-1)。
- 解析字符串中指定格式下不同位置,不同类型的数据:
c++
char *input = "name:Tom age:25 height:1.75";
char name[20];
int age;
float height;
sscanf(input, "name:%s age:%d height:%f", name, &age, &height);
printf("姓名:%s,年龄:%d,身高:%.2f\n", name, age, height);- 1231. 航班时间 :对于一个如下类型的航班时间格式各个部分的读取:
txt
17:21:07 00:31:46 (+1)c++
int h1, m1, s1, h2, m2, s2, d;
sscanf(line.c_str(), "%d:%d:%d %d:%d:%d (+%d)", &h1, &m1, &s1, &h2, &m2, &s2, &d);六、字符串&数字转换
6.1 字符串 -> 数字
- 头文件:
c++
#include <string>- 示例:
c++
#include <string>
using namespace std;
int num = stoi("123");
long num_l = stol("123456");
double num_d = stod("123.45");| 函数名 | 缩写全称 | 含义说明 |
|---|---|---|
| stoi | string to integer | 字符串转 int |
| stol | string to long | 字符串转 long |
| stoll | string to long long | 字符串转 long long |
| stof | string to float | 字符串转 float |
| stod | string to double | 字符串转 double |
| stold | string to long double | 字符串转 long double |
6.2 数字 -> 字符串
- 头文件:
c++
#include <string>- 示例:
c++
#include <string>
using namespace std;
// 整数 -> 字符串
int num = 123;
string str = to_string(num); // "123"
// 浮点数 -> 字符串
double d = 3.14;
string str_d = to_string(d); // "3.140000"七、初始化&备份神器
“内存级” 工具
memset/memcpy可以极快的效率完成初始化 / 备份,它比手写
for - loop可以快3 ~ 10倍
7.1 memset
- 头文件:
c++
#include <cstring> // 或者万能头 <bits/stdc++.h>- 1). 清零(最常用)
c++
int a[N];
memset(a, 0, sizeof(a)); // 每个字节置 0,整个数组变成 0- 2). 置
-1(利用补码特性,-1每个字节都是0xFF)
常用邻接表的初始化,把静态链表的头节点都指向
-1(NULL)
c++
// 使用邻接表来存储图
int h[N], w[N], e[N], ne[N], idx;
// ....
// 初始化邻接表表头
memset(h, -1, sizeof h);- 3). 置无穷大(只推荐
0x3f,原因见下)
求最短路时距离数组初始化为无穷大表示不可达
c++
int INF = 0x3f3f3f3f; // 10^9 级别,两倍相加不爆 int
memset(dist, 0x3F, sizeof(dist)); // 每个字节 0x3F,整体 0x3F3F3F3F- 4). 结构体清零
c++
struct Node { int x, y; bool vis; };
Node pool[M];
memset(pool, 0, sizeof(pool)); // 全部字段变 0 / false7.2 memcpy
- 头文件:
c++
#include <cstring> // 或者万能头 <bits/stdc++.h>- 1). 整型数组复制(比
for-loop快 3~5 倍)
比如说在
bellman_ford算法中dist需要先备份,后面使用备份来更新,防止 ”串联“ 操作
c++
int A[N], B[N];
//... // 计算完 A
memcpy(B, A, sizeof(A)); // B 变成 A 这一阶段的备份
// A 再去做其他计算 ...- 2). 结构体数组复制
c++
struct Pt { ll x, y; } p[N], bak[N];
memcpy(bak, p, sizeof(p)); // 备份整个点集- 3). 二维数组复制
c++
ll g[502][502], tmp[502][502];
memcpy(tmp, g, sizeof(g)); // 行主序连续,可直接拷7.3 总结
- 常用操作:
c++
memset(arr, 0, sizeof(arr)); // 清 0
memset(arr, -1, sizeof(arr)); // 置 -1
memset(arr, 0x3F, sizeof(arr)); // 置 INF
memcpy(dst, src, sizeof(src)); // 整块复制