在计算机科学中,C语言后缀自动机是一种强大的数据结构,用于高效处理字符串相关问题,例如子串查询、最长公共子串、不同子串数量统计等。本教程将用通俗易懂的方式,带领编程小白一步步理解并实现一个基础的后缀自动机。
后缀自动机(Suffix Automaton,简称 SAM)是一个有向无环图(DAG),它能以线性空间存储一个字符串的所有子串信息。对于长度为 n 的字符串,其后缀自动机最多只有 2n 个状态和 3n 条边,非常节省内存。

C 语言提供了对内存和指针的精细控制,非常适合实现底层数据结构。通过手写 C语言字符串处理逻辑,你能更深入理解后缀自动机的工作原理,同时提升算法能力。
我们将逐步构建一个支持动态添加字符的后缀自动机。以下是关键结构体定义:
#define MAXN 200000 // 最大字符数#define ALPHA 26 // 假设只处理小写字母struct State { int len; // 当前状态代表的最长子串长度 int link; // 后缀链接 int next[ALPHA]; // 转移数组};struct State st[MAXN * 2]; // 状态数组,最多 2n 个状态int sz; // 当前状态总数int last; // 当前字符串最后一个字符对应的状态初始化函数:
void sam_init() { // 初始化初始状态(状态0) st[0].len = 0; st[0].link = -1; for (int i = 0; i < ALPHA; i++) st[0].next[i] = -1; sz = 1; last = 0;}添加字符的核心函数(后缀自动机实现的关键):
void sam_extend(char c) { int cur = sz++; // 创建新状态 st[cur].len = st[last].len + 1; for (int i = 0; i < ALPHA; i++) st[cur].next[i] = -1; int p = last; // 沿着后缀链接向上遍历,设置转移 while (p != -1 && st[p].next[c - 'a'] == -1) { st[p].next[c - 'a'] = cur; p = st[p].link; } if (p == -1) { st[cur].link = 0; } else { int q = st[p].next[c - 'a']; if (st[p].len + 1 == st[q].len) { st[cur].link = q; } else { // 克隆状态 q int clone = sz++; st[clone].len = st[p].len + 1; for (int i = 0; i < ALPHA; i++) st[clone].next[i] = st[q].next[i]; st[clone].link = st[q].link; // 更新 q 和 cur 的后缀链接 st[q].link = st[cur].link = clone; // 修正之前的转移 while (p != -1 && st[p].next[c - 'a'] == q) { st[p].next[c - 'a'] = clone; p = st[p].link; } } } last = cur;}下面是一个完整的程序,读入一个字符串并构建其后缀自动机:
#include <stdio.h>#include <string.h>// ... 上面定义的结构体和函数 ...int main() { char s[100005]; scanf("%s", s); sam_init(); for (int i = 0; s[i]; i++) { sam_extend(s[i]); } printf("后缀自动机构建完成!总状态数:%d\n", sz); return 0;}掌握 后缀自动机教程中的知识后,你可以解决以下问题:
通过本教程,你已经掌握了 C语言后缀自动机的基本原理和实现方法。虽然初次接触可能觉得复杂,但只要理解状态、转移和后缀链接的关系,就能灵活运用这一强大工具。建议多动手调试代码,观察状态变化,加深理解。
继续练习吧!尝试用它解决实际问题,你会发现 C语言字符串处理的世界远比想象中精彩。
本文由主机测评网于2025-12-12发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025126432.html