数据结构_KMP字符串匹配算法(C语言)

本文深入讲解了KMP字符串匹配算法的原理与实现,包括简单模式匹配算法的正向与反向匹配过程,并详细阐述了如何利用最大相同前后缀序列进行快速匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构总目录

KMP字符串匹配算法

KMP算法是一种对简单模式匹配算法进行改进的字符串匹配算法
D.E.Knuth,J.H.MorrisV.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。
KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。

1. 简单模式匹配算法的正向匹配

1.1 图文解析

存在主字符串 mainStr 和需要匹配的子串 subStr
在这里插入图片描述
若发生匹配失败,主串指针回退到起点的下一个位置,子串指针则从头开始
在这里插入图片描述

1.2 源代码

#include <stdio.h>

int MatchSearch(char *mainStr, char *subStr, int len1, int len2)
{
    int i = 0, j = 0;
    while (i < len1 && j < len2)
    {
        if (mainStr[i] == subStr[j])
        {
        	// 向后匹配
            ++i;
            ++j;
        }
        else
        {
            // 主串指针回退到起点的下一个位置
            i = i - j + 1;
            // 子串指针从头开始
            j = 0;
        }
    }
    return j >= len2 ? i - len2 : -1;
}
 

int main()
{
    char mainStr[10] = "ababaababc";
    char subStr[5] = "ababc";

    int pos = MatchSearch(mainStr, subStr, 10, 5);
    if (pos > -1)
    {
        printf("匹配成功: %d\n", pos);
    }
    else
    {
        printf("匹配失败!\n");
    }
    
    return 0;
}

1.3 测试结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 简单模式匹配算法的反向匹配

2.1 图文解析

观察下图的简单匹配过程,我们可以发现
其实在a和c发生不匹配时,就可以判断出主串中[0,4](ababa)与子串(abaac)不匹配了
在这里插入图片描述
于是我们可以直接从子串结尾处开始进行判断
若发生不匹配,则回退到结尾处的下一个位置
在这里插入图片描述
在这里插入图片描述
若匹配成功,则可以反向进行匹配
在这里插入图片描述

2.2 源代码

#include <stdio.h>

int MatchSearch(char *mainStr, char *subStr, int len1, int len2)
{
    int i = len2 - 1, j = len2 - 1;
    // 从子串的最后一个位置开始查询
    while (i < len1 && j >= 0)
    {       
    	// 向前匹配
        if (mainStr[i] == subStr[j])
        {
            --i;
            --j; 
        }
        else
        {
            // 主串指针回退到开始位置的下一个位置
            i = i + (len2 - 1 - j) + 1;
            // 子串指针结尾开始
            j = len2 - 1;
            flag = i - len2 + 1;
        }
    }
    return j < 0 ? i + 1 : -1;
}
 

int main()
{
    char mainStr[10] = "ababaababc";
    char subStr[5] = "ababc";

    int pos = MatchSearch(mainStr, subStr, 10, 5);
    if (pos > -1)
    {
        printf("匹配成功: %d\n", pos);
    }
    else
    {
        printf("匹配失败!\n");
    }
    
    return 0;
}

2.3 测试结果

在这里插入图片描述
在这里插入图片描述

3. KMP字符串匹配算法

3.1 图文解析

一、观察如下图,我们发现在发生在不匹配位置之前的字符串【abab】是相同的,且存在最大相同前后缀序列【ab】
在这里插入图片描述
那么我们便可以根据最大相同前缀序列进行快速移动子串,如下图:
在这里插入图片描述
在这里插入图片描述

二、于是我们可以根据最大相同前后缀序列,将下次快速移动的位置存储在一个辅助数组中next【】中
在这里插入图片描述
代表当subStr[i]与主串发生不匹配时,可以根据next[i]快速定位下次匹配的位置为j
在这里插入图片描述
可以理解为简单模式匹配算法的反向匹配过程中,进行反向搜索的快速定位
在这里插入图片描述

3.2 源代码

#include <stdio.h>


void InitNext(int *next, char *subStr, int len)
{
    next[0] = -1;
    // (后缀结束下标 i) 和 (前缀结束下标 j)
    int i = 0, j = -1;
    while (i < len)
    {
        if (j == -1 || subStr[i] == subStr[j])
        {
            i++;
            j++;
            next[i] = j;
        }
        else
        {
            // 重新定位相同前缀、后缀的位置
            j = next[j];
        }
    }
}

int KMPSearch(char *mainStr, char *subStr, int len1, int len2)
{
    
    int next[len2];
    int i = 0, j = 0;
    
    // 初始化next数组
    InitNext(next, subStr, len2);
    
    // 根据next数组进行快速定位查找
    while (i < len1 && j < len2)
    {       
        if (j == -1 || mainStr[i] == subStr[j])
        {
            i++;
            j++;  
        }
        else
        {
            // 根据next数组快速定位下一个匹配的子串位置
            j = next[j]; 
        }
    }
    return j >= len2 ? i - len2 : -1;
}
 
int main()
{
    char mainStr[10] = "ababaababc";
    char subStr[5] = "ababc";

    int pos = KMPSearch(mainStr, subStr, 10, 5);
    if (pos > -1)
    {
        printf("匹配成功: %d\n", pos);
    }
    else
    {
        printf("匹配失败!\n");
    }
    
    return 0;
}

3.3 测试结果

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小-黯

免费的,尽力

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

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

打赏作者

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

抵扣说明:

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

余额充值