数据结构与算法:串的模式匹配算法

串的模式匹配算法概述

串的模式匹配是指在主串(文本串)中查找子串(模式串)出现的位置。这是字符串处理中的基础操作,广泛应用于文本编辑、搜索引擎、生物信息学等领域。常见的模式匹配算法包括朴素匹配算法、KMP算法、Boyer-Moore算法等。


朴素匹配算法(Brute-Force)

朴素匹配算法是最直观的模式匹配方法,通过逐个字符比较主串和模式串来实现。

算法思想
  1. 从主串的第一个字符开始,与模式串的第一个字符比较。
  2. 若匹配成功,继续比较后续字符;若匹配失败,主串回溯到起始位置的下一个字符,模式串从头开始。
  3. 重复上述过程,直到找到匹配的子串或主串遍历完毕。
时间复杂度
  • 最坏情况:O(m*n),其中m是主串长度,n是模式串长度。
C语言实现
#include <stdio.h>
#include <string.h>

int bruteForceMatch(char *text, char *pattern) {
    int textLen = strlen(text);
    int patternLen = strlen(pattern);
    
    for (int i = 0; i <= textLen - patternLen; i++) {
        int j;
        for (j = 0; j < patternLen; j++) {
            if (text[i + j] != pattern[j]) {
                break;
            }
        }
        if (j == patternLen) {
            return i; // 返回匹配的起始位置
        }
    }
    return -1; // 未找到匹配
}

int main() {
    char text[] = "ABABDABACDABABCABAB";
    char pattern[] = "ABABCABAB";
    int pos = bruteForceMatch(text, pattern);
    
    if (pos != -1) {
        printf("Pattern found at index %d\n", pos);
    } else {
        printf("Pattern not found\n");
    }
    return 0;
}

举例说明

主串:"ABABDABACDABABCABAB",模式串:"ABABCABAB"

  • 从主串第一个字符开始比较,发现不匹配时,主串指针后移一位,重新比较。

KMP算法(Knuth-Morris-Pratt)

KMP算法通过预处理模式串,利用部分匹配信息避免不必要的回溯,提高匹配效率。

算法思想
  1. 预处理模式串,生成next数组,记录模式串中每个位置的最长公共前后缀长度。
  2. 匹配过程中,若字符不匹配,根据next数组跳过部分字符,避免主串回溯。
时间复杂度
  • 预处理:O(n)
  • 匹配:O(m)
  • 总体:O(m+n)
C语言实现
#include <stdio.h>
#include <string.h>

void computeLPSArray(char *pattern, int patternLen, int *lps) {
    int len = 0;
    lps[0] = 0;
    int i = 1;
    
    while (i < patternLen) {
        if (pattern[i] == pattern[len]) {
            len++;
            lps[i] = len;
            i++;
        } else {
            if (len != 0) {
                len = lps[len - 1];
            } else {
                lps[i] = 0;
                i++;
            }
        }
    }
}

int KMPSearch(char *text, char *pattern) {
    int textLen = strlen(text);
    int patternLen = strlen(pattern);
    int lps[patternLen];
    
    computeLPSArray(pattern, patternLen, lps);
    
    int i = 0, j = 0;
    while (i < textLen) {
        if (pattern[j] == text[i]) {
            i++;
            j++;
        }
        if (j == patternLen) {
            return i - j; // 返回匹配的起始位置
        } else if (i < textLen && pattern[j] != text[i]) {
            if (j != 0) {
                j = lps[j - 1];
            } else {
                i++;
            }
        }
    }
    return -1; // 未找到匹配
}

int main() {
    char text[] = "ABABDABACDABABCABAB";
    char pattern[] = "ABABCABAB";
    int pos = KMPSearch(text, pattern);
    
    if (pos != -1) {
        printf("Pattern found at index %d\n", pos);
    } else {
        printf("Pattern not found\n");
    }
    return 0;
}

举例说明

模式串:"ABABCABAB"next数组为[0, 0, 1, 2, 0, 1, 2, 3, 4]

  • 当主串和模式串在某个位置不匹配时,根据next数组跳过部分字符,避免主串回溯。

Boyer-Moore算法

Boyer-Moore算法利用坏字符规则和好后缀规则,跳过大量不必要的比较,适合处理大字符集(如英文文本)。

算法思想
  1. 坏字符规则:当主串与模式串不匹配时,根据坏字符在模式串中的位置,计算移动距离。
  2. 好后缀规则:当模式串中存在与好后缀匹配的子串时,计算移动距离。
时间复杂度
  • 最坏情况:O(m*n)
  • 平均情况:O(m/n)
C语言实现(简化版)
#include <stdio.h>
#include <string.h>
#define NO_OF_CHARS 256

int max(int a, int b) {
    return (a > b) ? a : b;
}

void badCharHeuristic(char *pattern, int patternLen, int badchar[NO_OF_CHARS]) {
    for (int i = 0; i < NO_OF_CHARS; i++) {
        badchar[i] = -1;
    }
    for (int i = 0; i < patternLen; i++) {
        badchar[(int)pattern[i]] = i;
    }
}

int BMSearch(char *text, char *pattern) {
    int textLen = strlen(text);
    int patternLen = strlen(pattern);
    int badchar[NO_OF_CHARS];
    
    badCharHeuristic(pattern, patternLen, badchar);
    
    int s = 0;
    while (s <= (textLen - patternLen)) {
        int j = patternLen - 1;
        while (j >= 0 && pattern[j] == text[s + j]) {
            j--;
        }
        if (j < 0) {
            return s; // 返回匹配的起始位置
        } else {
            s += max(1, j - badchar[text[s + j]]);
        }
    }
    return -1; // 未找到匹配
}

int main() {
    char text[] = "ABABDABACDABABCABAB";
    char pattern[] = "ABABCABAB";
    int pos = BMSearch(text, pattern);
    
    if (pos != -1) {
        printf("Pattern found at index %d\n", pos);
    } else {
        printf("Pattern not found\n");
    }
    return 0;
}

举例说明

主串:"ABABDABACDABABCABAB",模式串:"ABABCABAB"

  • 利用坏字符规则,当不匹配时,跳过多个字符,减少比较次数。

总结

  1. 朴素匹配算法:简单直观,但效率低,适合短文本和小模式串。
  2. KMP算法:通过预处理模式串,避免主串回溯,适合重复模式较多的场景。
  3. Boyer-Moore算法:利用坏字符和好后缀规则,适合大字符集和长模式串。

根据实际需求选择合适的算法,权衡时间复杂度和实现复杂度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值