在计算机科学中,后缀数组(Suffix Array)是一种用于高效处理字符串问题的重要数据结构。它广泛应用于生物信息学、全文检索、数据压缩等领域。本教程将带你从零开始,用C++语言实现后缀数组,并详细解释其原理,即使是编程小白也能轻松掌握。
给定一个字符串 S,它的所有后缀是指从每个位置开始到字符串末尾的子串。例如,字符串 "banana" 的所有后缀为:
bananaananananaananaa将这些后缀按字典序排序后,记录它们原始起始位置的数组,就是后缀数组。
对于 "banana",排序后的后缀顺序为:
a → 起始位置 5ana → 起始位置 3anana → 起始位置 1banana → 起始位置 0na → 起始位置 4nana → 起始位置 2因此,后缀数组为:[5, 3, 1, 0, 4, 2]。

后缀数组可以高效解决以下问题:
相比后缀树,后缀数组更节省内存,且实现相对简单,是C++字符串处理中的常用技巧。
最直观的方法是生成所有后缀,然后排序。但这种方法时间复杂度为 O(n² log n),效率较低。我们可以使用更高效的 O(n log n) 算法——倍增法(Doubling Algorithm)。
我们逐步对每个后缀的前 1、2、4、8... 个字符进行排序,每次利用上一轮的排序结果加速当前轮次。通过维护“排名”数组,我们可以快速比较两个后缀的大小。
以下是完整的 C++后缀数组实现:
#include <iostream>#include <vector>#include <algorithm>#include <string>using namespace std;vector<int> buildSuffixArray(const string& s) { int n = s.length(); vector<int> sa(n), rank(n), temp(n); // 初始化:按单个字符排序 for (int i = 0; i < n; ++i) { sa[i] = i; rank[i] = s[i]; } // 倍增 for (int k = 1; k < n; k *= 2) { // 按 (rank[i], rank[i+k]) 排序 auto cmp = [&](int i, int j) { if (rank[i] != rank[j]) return rank[i] < rank[j]; int ri = (i + k < n) ? rank[i + k] : -1; int rj = (j + k < n) ? rank[j + k] : -1; return ri < rj; }; sort(sa.begin(), sa.end(), cmp); // 重新计算 rank temp[sa[0]] = 0; for (int i = 1; i < n; ++i) { temp[sa[i]] = temp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0); } rank = temp; } return sa;}int main() { string s = "banana"; auto sa = buildSuffixArray(s); cout << "后缀数组: "; for (int idx : sa) { cout << idx << " "; } cout << endl; return 0;}
运行上述代码,输出为:
后缀数组: 5 3 1 0 4 2
这正是我们前面手动计算的结果!
假设你需要在一个大型DNA序列中查找某个基因片段,使用后缀数组实现可以快速定位所有出现位置。此外,在文本编辑器中实现“查找所有匹配项”功能时,后缀数组也是底层关键技术之一。
通过本教程,你已经掌握了:
后缀数组是字符串算法中的基石之一。掌握它,将为你打开高效字符串处理的大门。建议你动手敲一遍代码,加深理解!
如果你觉得本文有帮助,欢迎分享给正在学习 C++字符串处理 的朋友!
本文由主机测评网于2025-12-27发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/20251213059.html