【字符串匹配算法介绍】


前言

字符串匹配算法是计算机科学中非常重要的内容,广泛应用于文本编辑、信息检索、生物信息学等领域。本文将详细介绍几种经典的字符串匹配算法,并给出对应的C++实现代码,包括:

  • 朴素字符串匹配算法(Naive)
  • KMP算法(Knuth-Morris-Pratt)
  • BM算法(Boyer-Moore)

通过这些算法的学习,读者不仅能理解字符串匹配的基本原理,还能掌握优化匹配效率的实用技巧。


一、字符串匹配算法简介

字符串匹配的任务是判断一个模式串 pattern 是否出现在主串 text 中,如果出现,返回匹配的位置,否则返回未找到。

最简单的方式是朴素匹配,暴力尝试所有可能的起点,时间复杂度为 O(mn),其中 m 是模式串长度,n 是主串长度。效率较低。

为提升效率,研究者设计了 KMP、BM 等算法,通过利用匹配失败时的信息避免重复比较,实现线性甚至接近线性的时间复杂度。


二、朴素字符串匹配算法

1. 算法原理

从主串的每个位置开始尝试匹配模式串,如果某字符不匹配,则移动主串起点向后一个位置,继续尝试。

2. 代码示例

#include <iostream>
#include <string>

int naiveSearch(const std::string& text, const std::string& pattern) {
    int n = text.size();
    int m = pattern.size();
    for (int i = 0; i <= n - m; i++) {
        int j = 0;
        while (j < m && text[i + j] == pattern[j]) {
            j++;
        }
        if (j == m) {
            return i; // 找到匹配,返回位置
        }
    }
    return -1; // 未找到匹配
}

int main() {
    std::string text = "hello world";
    std::string pattern = "world";

    int pos = naiveSearch(text, pattern);
    if (pos != -1) {
        std::cout << "匹配成功,位置:" << pos << std::endl;
    } else {
        std::cout << "未找到匹配" << std::endl;
    }
    return 0;
}

三、KMP算法(Knuth-Morris-Pratt)

1. 算法原理

KMP算法核心是利用已经匹配过的部分信息,避免回溯主串的指针。其关键在于计算模式串的“最长前缀后缀表”(next数组),表示当前位置之前子串的最大相等前后缀长度。

匹配失败时,根据next数组移动模式串位置,达到时间复杂度O(m + n)。

2. 计算next数组代码

#include <vector>
#include <string>

std::vector<int> computeNext(const std::string& pattern) {
    int m = pattern.size();
    std::vector<int> next(m, 0);
    int j = 0; // 前缀末尾指针
    for (int i = 1; i < m; i++) {
        while (j > 0 && pattern[i] != pattern[j]) {
            j = next[j - 1]; // 回溯
        }
        if (pattern[i] == pattern[j]) {
            j++;
        }
        next[i] = j;
    }
    return next;
}

3. KMP主匹配函数

int kmpSearch(const std::string& text, const std::string& pattern) {
    if (pattern.empty()) return 0;
    int n = text.size();
    int m = pattern.size();
    std::vector<int> next = computeNext(pattern);
    int j = 0; // 模式串指针

    for (int i = 0; i < n; i++) {
        while (j > 0 && text[i] != pattern[j]) {
            j = next[j - 1]; // 根据next数组回溯模式串指针
        }
        if (text[i] == pattern[j]) {
            j++;
        }
        if (j == m) {
            return i - m + 1; // 匹配成功,返回位置
        }
    }
    return -1; // 未找到匹配
}

4. 测试示例

int main() {
    std::string text = "abxabcabcaby";
    std::string pattern = "abcaby";

    int pos = kmpSearch(text, pattern);
    if (pos != -1) {
        std::cout << "KMP匹配成功,位置:" << pos << std::endl;
    } else {
        std::cout << "未找到匹配" << std::endl;
    }
    return 0;
}

四、Boyer-Moore算法简介

BM算法采用“坏字符规则”和“好后缀规则”,跳跃式移动模式串,通常在实际文本中表现优于KMP。实现较复杂,此处只简单介绍。

  • 坏字符规则:匹配失败时,将模式串向右滑动,使得坏字符对齐模式串中该字符的最后一次出现。
  • 好后缀规则:匹配失败时,根据已经匹配的后缀,在模式串中找到另一个相同的后缀进行对齐。

BM算法适合模式串较长,文本较大场景。


总结

本文介绍了三种字符串匹配算法的基本原理和C++实现:

  • 朴素算法,简单直接,但效率低。
  • KMP算法,利用next数组实现高效匹配,时间复杂度O(m+n)。
  • Boyer-Moore算法,基于启发式跳跃,实际效率很高。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wdwc2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值