KMP 快速匹配算法

最近学习了KMP快速匹配算法,自己动手尝试着编写,最终也完成了该算法,理清思路后发表该博客,希望不懂的小白可以参考(我也是小白)

      首先KMP算法是字符串快速匹配算法。简而言之就是快速在一个字符串里查找相应的内容。比如word的查找功能

模拟应用场景: 在asdasdasdddasdasd  快速找到asddd第一次出现时对应下标。

一般的串匹配算法(非KMP算法)

KMP算法:

设主串(T)为:a b a c a a b a c a b a c a b a a b b

模式串(W)为:a b a c a b

而在KMP算法中,对于每一个模式串我们会事先计算出模式串的内部匹配信息,在匹配失败时最大的移动模式串,以减少匹配次数。

比如,在简单的一次匹配失败后,我们会想将模式串尽量的右移和主串进行匹配。右移的距离在KMP算法中是如此计算的:在已经匹配的模式串子串中,找出最长的相同的前缀后缀,然后移动使它们重叠。

在第一次匹配过程中

T :   a b c a b c a b c a a a b c

W:   a b c a b c a a

在T[7]与W[7]出现了不匹配,而T[0]~T[6]是匹配的,现在T[0]~T[6]就是上文中说的已经匹配的模式串子串,现在移动找出最长的相同的前缀和后缀并使他们重叠:移动一次出现以下(仅仅一次)

T :   a b c a b c a b c a a a b c

W:            a b c a b c a a

此时直接从W[4]与T[7]开始一一对应往下匹配,发现立即找到了符合条件的下标

然后在从上次匹配失败的地方进行匹配,这样就减少了匹配次数,增加了效率。

但是如何找到W[4],让其与T[7]开始匹配首先我们分析下a b c a b c a a这个数据

当a b c a b c a a中红色a与T开始匹配时,失陪(没有匹配成功)但是前面的abc出现了两次也就说明T串中前7个是匹配成功的。

此时我们可以直接让W[0]与T[3]对应,对应后发现

T :   a b c a b c a b c a a a b c

W:            a b c a b c a a

W中红色b之前的还是匹配的,也就是T[7]不需要回到T[3]开始匹配。这样的话我们只需要找到移动W串相应的步数即可!

j下标01234567
W[j]abcabcaa
F(j)00001231

F(j)为不需要匹配的个数(即从F(j)出开始匹配)如W[6]对应的F[j]为3  即为W中前三个不需要匹配.

以下为计算F[j]代码:

int *getfreq(char *str) {
    int *freq = NULL;
    int i = 0;
    int j = -1;
    
    freq = (int *) calloc(strlen(str) + 1, sizeof(int));
    freq[0] = -1;
    while(i < strlen(str)) {
        if(j == -1 || str[j] == str[i]){
            i++;
            j++;
            freq[i] = j;
        }
        else{
            j = freq[j];
        }    
    }
    freq[0] = 0;
    return freq;
}

做到这一步已经完成了一大半:下面就是用freq数组进行移动!

整体代码如下

#include <stdio.h>
#include <malloc.h>
#include <string.h>

void getindex(char *str1, char *str2, int *freq) {
    int i = 0;
    int j = 0;
    int flog = 1;
    
    while(str1[i] != 0 && flog == 1){
        if(str1[i] == str2[j]){
            i++;
            j++;
        }
        else{
            j = freq[j];
            i++;
        }
        if(j == strlen(str2)){
            flog = 0;
        }
    }
    if(flog != 0){
        printf("没有找到");
    }
    else{
        printf("第一次该内容对应的下标为:%d", i - strlen(str2));
    }
}
int *getfreq(char *str) {
    int *freq = NULL;
    int i = 0;
    int j = -1;
    
    freq = (int *) calloc(strlen(str) + 1, sizeof(int));
    freq[0] = -1;
    while(i < strlen(str)) {
        if(j == -1 || str[j] == str[i]){
            i++;
            j++;
            freq[i] = j;
        }
        else{
            j = freq[j];
        }    
    }
    freq[0] = 0;
    /*for(i = 0; i < strlen(str); i++){
        printf("%d",freq[i]);
    }*/
    return freq;
}
int main(){
    char s1[100];
    char s2[100];
    int *freq = NULL;
    
    printf("请输入源字符串:\n");
    gets(s1);
    printf("请输入要查找的内容:\n");
    gets(s2);
    freq = getfreq(s2);
    getindex(s1, s2, freq);
    free(freq);
    return 0;
}

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法(Knuth-Morris-Pratt算法)是一种用于解决字符串匹配问题的高效算法。它的主要思想是利用匹配失败时的信息,尽量减少比较次数,提高匹配效率。 KMP算法的核心是构建一个部分匹配表(Partial Match Table),也称为Next数组。这个表记录了在匹配失败时应该将模式串向右移动的位置。 构建部分匹配表的过程如下: 1. 首先,将模式串中的第一个字符的Next值设为0,表示当匹配失败时,模式串不需要移动; 2. 然后,从模式串的第二个字符开始,依次计算Next值; 3. 当第i个字符与前面某个字符相同的时候,Next[i]的值为该字符之前(不包括该字符)的相同前缀和后缀的最大长度; 4. 如果不存在相同的前缀和后缀,则Next[i]的值为0。 有了部分匹配表之后,KMP算法匹配过程如下: 1. 用i和j来分别表示模式串和主串的当前位置; 2. 如果模式串中的字符和主串中的字符相同,那么i和j都向右移动一位; 3. 如果模式串中的字符和主串中的字符不同,那么根据部分匹配表来确定模式串的下一个位置; 4. 假设当前模式串的位置为i,根据部分匹配表中的值Next[i],将模式串向右移动Next[i]个位置; 5. 重复上述步骤,直到找到匹配或者主串遍历完毕。 KMP算法的时间复杂度为O(m + n),其中m和n分别是模式串和主串的长度。相比于暴力匹配算法的时间复杂度为O(m * n),KMP算法能够大幅减少比较次数,提高匹配效率。 综上所述,KMP模式匹配算法通过构建部分匹配表并利用匹配失败时的信息,实现了高效的字符串匹配。在实际应用中,KMP算法被广泛地应用于文本编辑、数据搜索和字符串处理等领域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值