算法题常用技巧

前面几篇讲了 C 语言的语法和数据结构,已经够你看懂大部分代码了。这篇补充一些在刷算法题时经常会用到的实用技巧,都是一些零散但重要的知识点。

ACM 模式 I/O 模板

很多 OJ 平台(包括本站)使用 ACM 模式,需要你自己处理输入输出。前面基础语法篇已经介绍过 scanfprintf 的用法,这里给一个完整的 ACM 模式模板:

排序

qsort 基本用法

C 标准库提供了 qsort 函数来排序数组,它需要你传入一个比较函数来指定排序规则:

比较函数的参数是 const void*(通用指针),需要先转换成实际类型再比较。*(int*)a 的意思是:先把 void* 转成 int*,再解引用得到 int 值。这个写法是固定套路,记住就行。

注意比较函数不要直接写 return *(int*)a - *(int*)b;,虽然很多教程这样写,但当数值范围较大时(比如 INT_MAX 和负数相减)会整数溢出,导致排序结果错误。用 if 判断更安全。

对结构体数组排序

多级排序

有时需要按多个条件排序,比如先按分数降序,分数相同再按名字字典序:

对二维数组排序

算法题中经常需要对二维数组排序(比如区间合并问题,按区间起点排序)。C 语言中二维数组的排序稍微有点绕:

常用数学操作

整数边界值

intlong long 都有范围限制,超出范围会溢出:

算法题中最常见的溢出场景是两个 int 相加或相乘,结果超出 int 范围。遇到这种情况,把其中一个操作数转成 long long 就行:

int a = 100000, b = 100000;
// 错误:int * int 结果还是 int,会溢出
int wrong = a * b;
// 正确:先转 long long 再乘
long long right = (long long)a * b;

常用工具函数

C 语言没有内置的 maxminswap 函数,需要自己写。在刷题时把这几个函数放在代码开头就行:

优先队列模板(手写二叉堆)

C 语言没有内置的优先队列,需要手写二叉堆。虽然比较繁琐,但可以把下面的模板代码直接复制使用。

优先队列在 Dijkstra 最短路径、合并 K 个有序链表等算法题中大量使用。关于二叉堆的原理,可以参考 二叉堆核心原理及可视化,这里只给出实用的模板。

如果需要大顶堆,只需把比较方向反转:heapPush 中的 < 改为 >heapPop 中的 < 改为 ><= 改为 >=

进制转换

有些算法题会涉及进制相关的问题,了解标准库提供的进制转换函数,就不需要自己手搓转换逻辑了。C 语言可以用 printf 的格式说明符直接输出不同进制,用 strtol 解析其他进制的字符串:

C 语言输出八进制和十六进制直接用 printf%o%x 就行,很方便。但 C 标准没有提供直接输出二进制的格式符,需要手动用位运算转换。解析其他进制的字符串用 strtol,第三个参数指定进制。

小结

这篇介绍的技巧在刷题中会反复用到。scanf/printf 处理输入输出,qsort 配合比较函数实现排序,计算可能越界时记得转 long longmaxminswap 三件套可以直接复制到代码开头。优先队列用手写二叉堆模板,也是直接复制使用。

学到这里,C 语言刷题所需的基础知识就全部介绍完了。这些知识足够你看懂本站的所有 C 语言算法代码了。接下来就可以开始刷题了,边刷边查,很快就能熟练起来。