简单模式匹配算法
简单模式匹配算法,就是用模式串去跟主串进行匹配,从主串的第一个字符开始与模式串进行匹配,若主串中字符与模式串中字符匹配失败,则从主串的第二个字符开始与模式串的第一个字符开始匹配,以此类推,若整个模式串匹配成功,则返回位置。
主 串: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];
}
}