2022.12.10
int Index1(SString S,SString T){
/**
* 朴素模式匹配算法1(用于展示)
*
* 返回匹配位置,匹配失败返回0
*/
int i=1;
SString Sub;
while(i<=S.length - T.length +1){
SubString(Sub,S,i,T.length);
PrintNSpace(i-1);
StrPrint(Sub); // test
if(StrCompare(Sub,T)!=0){
i++;
printf(" --- x\n"); // test
}
else{
printf(" --- √\n"); // test
return i;
}
}
return 0;
}
int Index2(SString S,SString T){
/**
* 朴素模式匹配算法2
*
* 返回匹配位置,匹配失败返回0
*/
int i=1,j=1;
while(i<=S.length && j<=T.length){
if(S.ch[i]==T.ch[j]){
i++;j++; //同时后移
}else{
i=i-j+2; // i从下一位重新计算
j=1; // j也回到开头
}
}
if(j>T.length)
// 匹配成功
return i-T.length;
else
// 匹配失败
return 0;
}
讲的非常好的课:木子喵的KMP
计算部分匹配值:从前1个到前n个,分别计算前缀集合和后缀集合最长的相等元素长度。
比如char str[] ="ababa"
:
前n个字符 | 前缀 | 后缀 | 最长相等长度 |
---|---|---|---|
a | {} | {} | 0 |
ab | {a} | {b} | 0 |
aba | {a,ab} | {ba,a} | 1 |
abab | {a,ab,aba} | {bab,ab,b} | 2 |
ababa | {a,ab,aba,abab} | {baba,aba,ba,a} | 3 |
部分匹配值:00123
移动位数 = 已匹配位数 - 部分匹配值
改进算法——Next数组
int Index3(SString S,SString T){
/**
* KMP算法(演示版)
*
* 返回匹配位置,匹配失败返回0
*/
// 计算next数组
int next[T.length];
SString temp1;
SString temp2;
for(int i=1;i<T.length+1;i++){
if(i==1){
next[i]=0;
continue;
}else if(i==2){
next[i]=1;
continue;
}
for(int j=1;j<i;j++){
SubString(temp1,T,1,j); // 前缀
SubString(temp2,T,i-j,j); // 后缀
if(StrCompare(temp1,temp2)==0){
next[i]=j;
break;
}else{
next[i]=1;
}
}
}
for(int i=1;i<T.length+1;i++){
printf("%d ",next[i]);
}
printf("\n");
// 模式匹配
int i=1,j=1,count=1,temp=0;
StrPrintln(T);
while(i<=S.length && j<=T.length){
//printf("%d(%d) %d(%d) %d\n",i,S.length,j,T.length,count);
count++;
if(S.ch[i]==T.ch[j]){
//printf("√--%d:%c %d:%c\n",i,S.ch[i],j,T.ch[j]);
i++;j++; //同时后移
}else{
//printf("x--%d:%c %d:%c\n",i,S.ch[i],j,T.ch[j]);
temp=j; // for test
j=next[j];
if(j==0){
i++;j=1;
}
//printf("-->%d:%c %d:%c\n",i,S.ch[i],j,T.ch[j]);
PrintNSpace(i-1);
StrPrint(T);
printf(" next[%d]:%d\n",temp,next[temp]);
}
}
if(j>T.length)
// 匹配成功
return i-T.length;
else
// 匹配失败
return 0;
}
int Index4(SString S,SString T){
/**
* KMP算法(演示版)
*
* 返回匹配位置,匹配失败返回0
*/
// 计算next数组
int next[T.length];
SString temp1;
SString temp2;
for(int i=1;i<T.length+1;i++){
if(i==1){
next[i]=0;
continue;
}else if(i==2){
next[i]=1;
continue;
}
for(int j=1;j<i;j++){
SubString(temp1,T,1,j); // 前缀
SubString(temp2,T,i-j,j); // 后缀
if(StrCompare(temp1,temp2)==0){
next[i]=j;
break;
}else{
next[i]=1;
}
}
}
// 模式匹配
int i=1,j=1,count=1;
while(i<=S.length && j<=T.length){
count++;
if(S.ch[i]==T.ch[j]){
i++;j++; //同时后移
}else{
j=next[j];
if(j==0){
i++;j=1;
}
}
}
if(j>T.length)
// 匹配成功
return i-T.length;
else
// 匹配失败
return 0;
}
【2015 统考真题】已知字符串S为’abaab[a]abacacaabaabcc",模式串t为'abaab[c]".采用KMP 算法进行匹配,第一次出现“失配”(S[i]≠t[j])时,i=j=5,則下次开始匹配时,i和j的值分别是()。 A. i=1, j=0 B. i=5, j=0 C. i=5, j=2 D. ¡=6, j=2
【答案】:
前n个字符 | 前缀 | 后缀 | 最长相等长度 | NEXT |
---|---|---|---|---|
a | {} | {} | 0 | -1 |
ab | {a} | {b} | 0 | 0 |
aba | {a,ab} | {ba,a} | 1 | 0 |
abaa | {a,ab,aba} | {baa, aa,a} | 1 | 1 |
abaab | {a,ab,aba.abaa} | {baab,aab,ab,b} | 2 | 1 |
abaaba | {a,ab,aba.abaa,abaab} | {baaba,aaba,aba,ba,a} | 3 | 2 |
主字符串指针不变,子字符串指针退回到next[j] = next[5] = 2,C
【2019 统考真题】设主串I='abaabaabcabaabc',模式串S'abaabc",来用 KMP算法进行模式匹配,到匹配成功时为止,在匹配过程中进行的单个字符间的比较次数是()。 A. 9 B. 10 C. 12 D. 15
【答案】:
[a] [b] [a] [a] [b] [a] abcabaabc,[a]baabc, 6
abaab [a] [a] [b] [c] abaabc,ab[a]abc, 4,B