跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

数据结构详解:KMP 算法、Trie 树与并查集

综述由AI生成介绍 KMP 算法、Trie 树及并查集三种核心数据结构。KMP 算法通过预处理模式串的 next 数组优化字符串匹配过程,避免回溯;Trie 树利用前缀共享特性高效存储和检索字符串集合;并查集通过树形结构管理不相交集合,支持合并与查询操作,并可通过路径压缩和按秩合并优化效率。文中提供了基于 C++ 的标准实现模板及关键逻辑解析。

接口猎人发布于 2026/2/8更新于 2026/5/2325 浏览
数据结构详解:KMP 算法、Trie 树与并查集

数据结构详解:KMP 算法、Trie 树与并查集

KMP 算法

KMP 算法主要用于解决字符串匹配问题。给定主串 S[](较长)和模式串 P[],KMP 算法通常使用下标从 1 开始遍历。

暴力匹配思路

暴力做法是每当匹配到不一致的字符时,将 P 串从头开始,与 S 串的起点后移一位的位置重新匹配。当串长度很长时,这种方法会导致超时。

for(int i = 1; i <= m; i ++){
    bool flag = true;
    for(int j = 1; j <= n; j++){
        if(S[i+j-1] != P[j]){
            flag = false;
            break;
        }
    }
}

原理

暴力匹配每次遇到不同字符都让 P 从头开始,但 P 串本身存在相同的前缀和后缀。当匹配失败时,无需逐个回退,可直接跳到特定位置继续匹配。

文章配图

Next 数组

Next 数组的含义是以 i 为终点的后缀和从 1 开始的前缀相等的最长长度。 即 next[i] = j 表示 P[1...j] == P[i-j+1...i]。

计算方法:假设 i-1 位置之前的最长前缀后缀长度为 j,若 P[i] == P[j+1],则 j++,令 next[i] = j;否则利用 next[j] 继续回溯匹配。

// 求 next 数组
for(int i = 2, j = 0; i <= n; i ++){
    while(j && P[i] != P[j + 1]) j = ne[j];
    if(P[i] == P[j + 1]) j ++;
    ne[i] = j;
}

匹配过程

明确指针后,每次比较 j+1 和 i 位置是否相同。不同则 j 回退到 ne[j],相同则 j++。

// KMP 匹配模板
#include<iostream>
using namespace std;
const int N = 1e4 + 10;
const int M = 1e5 + 10;
char S[M], P[N], ne[N];
int n, m;

int main(){
    cin >> n >> (P + 1) >> m >> (S + 1);
    // 求 next 过程
    for(int i = 2, j = 0; i <= n; i ++){
        while(j && P[i] != P[j + 1]) j = ne[j];
        if(P[i] == P[j + 1]) j ++;
        ne[i] = j;
    }
    // 匹配过程
    for(int i = 1, j = 0; i <= m; i ++){
        while(j && S[i] != P[j + 1]) j = ne[j];
        if(S[i] == P[j + 1]) j ++;
        if(j == n){
            printf("%d ", i - n);
            j = ne[j];
        }
    }
    return 0;
}

Trie 树

Trie 树(字典树)用来快速存储和查找字符串集合。

文章配图

文章配图

插入时将单词字母一一存入,根节点为 0。最后一个字母做标记以区分完整单词。

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
char str[N];
int son[N][26], cnt[N], idx;

// 插入操作
void insert(char str[]){
    int p = 0;
    for(int i = 0; str[i]; i ++){
        int u = str[i] - 'a';
        if(!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
    cnt[p]++;
}

// 查询操作
int query(char str[]){
    int p = 0;
    for(int i = 0; str[i]; i ++){
        int u = str[i] - 'a';
        if(!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

int main(){
    int n;
    scanf("%d", &n);
    while(n --){
        char op[2];
        scanf("%s%s", op, str);
        if(op[0]=='I') insert(str);
        else printf("%d\n", query(str));
    }
    return 0;
}

并查集

并查集用于处理集合合并及元素所属集合判断的问题。

基本原理: 每个集合用一棵树表示,树根编号即为集合编号,p[x] 存储 x 的父节点。

  1. 判断树根: if(p[x] == x)
  2. 求集合编号: while(p[x] != x) x = p[x];
  3. 合并集合: p[find(x)] = find(y);

优化: 路径压缩。

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int p[N], n, m;

int find(int x){
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++) p[i] = i;
    while(m --){
        char op[2];
        int a, b;
        scanf("%s%d%d", op, &a, &b);
        if(op[0] == 'M') p[find(a)] = find(b);
        else{
            if(find(a) == find(b)) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

若需统计每个集合的元素数量,可添加 size 数组。合并时累加 size,同集合则跳过。

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int p[N], n, m, sizes[N];

int find(int x){
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++) p[i] = i, sizes[i] = 1;
    while(m --){
        char op[5];
        int a, b;
        scanf("%s", op);
        if(op[0] == 'C') {
            scanf("%d%d", &a, &b);
            if(find(a) == find(b)) continue;
            sizes[find(b)] += sizes[find(a)];
            p[find(a)] = find(b);
        } else if(op[1] == '1'){
            scanf("%d%d", &a, &b);
            if(find(a) == find(b)) puts("Yes");
            else puts("No");
        } else {
            scanf("%d", &a);
            printf("%d\n", sizes[find(a)]);
        }
    }
    return 0;
}

以上介绍了三种常见数据结构的核心实现与应用场景。

目录

  1. 数据结构详解:KMP 算法、Trie 树与并查集
  2. KMP 算法
  3. 暴力匹配思路
  4. 原理
  5. Next 数组
  6. 匹配过程
  7. Trie 树
  8. 并查集
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • RuoYi Office 开源 OA、HRM、CRM、ERP 一体化系统部署指南
  • AI Skills 核心概念与实战搭建指南
  • 2025 年 AI 数字人平台测评:5 款主流工具对比与推荐
  • AI 时代产品经理:厘清 AI 能力边界与技术限制
  • 腾讯云服务器部署 OpenClaw 对接飞书实战
  • 中文方言合成突破:粤语与四川话在 VoxCPM-1.5-TTS 中的表现
  • llama-cpp-python 完整安装与配置指南
  • C++原子操作:从底层原理到实战应用
  • 前端开发中 TypeError: Failed to fetch 错误的原因与解决方法
  • C++ 核心数据结构:Stack 与 Queue 类深度解析
  • VSCode Cline 集成 GPT-5.4 与 Copilot 模型配置指南
  • Stable Diffusion WebUI Windows 部署与常见报错解决方案
  • C++ 搜索引擎核心:基于正倒排索引的 Searcher 实现解析
  • MCP Document Reader:支持多格式文档解析的 AI 工具
  • AI 模型可解释性与安全防护结合指南
  • 2026 年 Gemini 学生计划实战指南:将免费 Pro 权限转化为 AI 求职优势
  • 《Virt A Mate(VAM)》免安装豪华版v1.22中文汉化整合
  • JavaScript filter 方法详解与实战
  • 2026最火的6款免费AI写作软件测评:ai写网文哪个好用?这款ai消痕工具
  • 顺序表基础概念、C 语言实现与典型算法解析

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online