考研数据结构笔记--串(2)——模式匹配

简单模式匹配算法

简单模式匹配算法,就是用模式串去跟主串进行匹配,从主串的第一个字符开始与模式串进行匹配,若主串中字符与模式串中字符匹配失败,则从主串的第二个字符开始与模式串的第一个字符开始匹配,以此类推,若整个模式串匹配成功,则返回位置。

主 串:a b a b c a b a a c a b
模式串:a b a a

第一趟匹配:
a b a b c a b a a c a b
a b a a

第二趟匹配:
a b a b c a b a a c a b
  a b a a

第三趟匹配:
a b a b c a b a a c a b
    a b a
……
直到
a b a b c a b a a c a b
  		  a b a a
匹配成功返回
实现代码
#include <stdio.h>
#include <string.h>

int pattern_match(char t[], char p[]){
    int len_t = strlen(t), len_p = strlen(p);
    int i = 0, j = 0;

    while(i < len_t && j < len_p){
        if(t[i] == p[j]){
            ++i;
            ++j;
        }else{
            i = i - j + 1;
            j = 0;
        }
    }
    if(j == len_p)
        return i - len_p;
    else
        return -1;

}

int main(){
    char s1[] = "ababcabaab";
    char s2[] = "abaa";
    int pos = pattern_match(s1, s2);
    printf("%d", pos);
    return 0;
}

KMP算法

KMP算法的核心思想就是尽可能多的跳过暴力匹配中不必要的匹配。

KMP算法中最重要的一步就是求next数组。当然,next数组求法很简单,以下标从1开始为例,next[1]=0这是固定的,然后下面的就是看这个字符前面的字符串中前缀和后缀相匹配的最大长度len(当然这个前缀长度要小于该字符串长度),那么next[k]=前k-1个字符中前缀和后缀相匹配的最大长度+1,但是要用算法实现起来就不那么容易理解了。

下 标:  1 2 3 4 5 6 7 8 9
模式串: a b a b c a b a a
next[]0 1 1 2 3 1 2 3 4

其中
next[1] = 0
next[2]的值,要看a的前缀和后缀最长匹配长度为0,0+1 = 1
next[3]的值,要看a b的前缀和后缀最长匹配长度为0,0+1 = 1
next[4]的值,要看a b a的前缀和后缀最长匹配长度为1,1+1 = 2
next[5]的值,要看a b a b的前缀和后缀最长匹配长度为2,2+1 = 3
以此类推
计算next数组代码
//next数组从下标1开始存储
void get_next(char p[],int next[]){
    int len_p = strlen(p);
    int len = 0, i = 1;
    next[1] = 0;

    while(i < len_p){
        if(len == 0 || p[i-1] == p[len-1]){
            ++i, ++len;
            next[i] = len;
        }else
            len = next[len];
    }
}
KMP算法主要代码
int kmp(char s[], char p[], int next[]){
    int i = 1, j = 1;
    int len_s = strlen(s), len_p = strlen(p);
    while(i <= len_s && j <= len_p){
        if(j == 0 || s[i-1] == p[j-1]){
            ++i;
            ++j;
        }
        else
            j = next[j];
    }

    if(j > len_p)
        return i - len_p;//返回的是位置,不是下标,若要返回下标减1即可
    else
        return 0;
}

改进的KMP算法

前面定义的next函数在某些情况下有些缺陷,如“a a a a b”在和主串“a a b a a a a b”匹配时当i= 4、j = 4时s[4]!=p[4],由next[j]的指示还需要进行i=4、i=3、i=2、i=1这三次比较。而这些比较也都是无用的,因为模式串中第1、2、3个字符和第4个字符都相等,所以可以省略这些操作,直接将模式一口气滑动4个字符。也就是直接进行i=5、j=1时的字符比较。那么我们只需要修改next函数修正值的算法

void get_nextval(char p[],int next[]){
    int len_p = strlen(p);
    int len = 0, i = 1;
    next[1] = 0;

    while(i < len_p){
        if(len == 0 || p[i-1] == p[len-1]){
            ++i, ++len;
            if(p[i-1] != p[len - 1])
                next[i] = len;
            else
                next[i] = next[len];
        }else
            len = next[len];
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值