《数据结构(严蔚敏版)》学习笔记(五)——串的模式匹配算法

来源:互联网 发布:学会python要多久 编辑:程序博客网 时间:2024/05/01 20:16

《数据结构(严蔚敏版)》学习笔记(五)——串的模式匹配算法


主串S,模串T,串首存串长(SString)

普通方法:当S[i]与T[j]失配时,i回溯到i-j+2,j回溯到1,重新开始匹配。T = O(m*n);

KMP方法:当S[i]与T[j]失配时,i不变,j根据失配字符的next值滑动,继续匹配。若j滑到0,则i++,重新匹配。T = O(m+n);


kmp算法难点:求模式串的next数组!!


j                    1 2 3 4 5 6 7 8

模式串 a b a a b c a c

next[j] 0 1 1 2 2 3 1 2


j1 2 3 4 5

模式串a a a a b

next[j]         0 1 2 3 4

nextval[j]     0 0 0 0 4


下面是模式匹配算法和动态演示next数组求法的程序...

<span style="font-size:14px;">/*-----$串的模式匹配算法$-----*///注:SString 的串,S[0]存串的长度#include <stdio.h>#include <stdlib.h>#include <string.h>#include <windows.h>//初始定义typedef intStatus;typedef charElemType;#defineOK1#defineERROR0#defineOVERFLOW-1#defineMAX_SIZE100typedef unsigned char SString[MAX_SIZE];void CreateString(SString &S,char T[]){int i;S[0] = strlen(T);for(i =0;i<=S[0];i++){S[i+1] = T[i];}}/*算法[求子串位置]---T = O(n*m)*///返回子串T在主串S第pos个字符之后的位置int Index(SString S,SString T,int pos){int i = pos,j = 1;while(i<=S[0] && j<=T[0]){if(S[i] == T[j]){++i;++j;}else{i = i-j+2;j=1;}}if(j>T[0])return i-T[0];elsereturn 0;}/*算法[KMP]---T = O(n+m)*///求模式串T的next函数值void get_next(SString T,int next[]){int i = 1,j = 0;next[1]=0;while(i<T[0]){if(T[i] == T[j] || j==0){++i;++j;next[i] = j;}else{j = next[j];}}}//求模式串T的nextval函数值void get_nextval(SString T,int nextval[]){int i=1,j=0;nextval[1] = 0;while(i<T[0]){if(T[i] == T[j] || j==0){++i;++j;if(T[i]!=T[j])nextval[i] = j;elsenextval[i] = nextval[j];}else{j = nextval[j];}}}//失配时,i不变,j回溯到next[j]处重新比较int Index_KMP(SString S,SString T,int pos){int i = pos,j = 1,nextval[MAX_SIZE];get_nextval(T,nextval);while(i<=S[0] && j<=T[0]){if(S[i] == T[j] || j == 0){++i;++j;}else{j = nextval[j];}}if(j>T[0])return i-T[0];elsereturn 0;}//展示KMP中求next数组流程——DisplayKMP函数 和 dynamic_next函数void DisplayKMP(SString T,int i,int j,int next[]){int n = T[0],k;for(k=0;k<=n;k++)printf("%d ",k);printf("\n");for(k=0;k<2*i;k++)printf(" ");printf("i");printf("\n  ");for(k=1;k<=n;k++)printf("%c ",T[k]);printf("\n  ");for(k=1;k<=n;k++)printf("%c ",T[k]);printf("\n");for(k=0;k<2*j;k++)printf(" ");printf("j");printf("\n  ");for(k=1;k<=i;k++)printf("%d ",next[k]);printf("\n-------------------\n");Sleep(1000);}void Dynamic_next(SString T){int next[100];int i = 1,j = 0;next[1]=0;system("cls");DisplayKMP(T,i,j,next);system("cls");while(i<T[0]){if(T[i] == T[j] || j==0){++i;++j;next[i] = j;}else{j = next[j];}DisplayKMP(T,i,j,next);system("cls");}}int main(){SString S,T;char input[100] = {"I love programming on my computer!"};char model[100] = {"abaabcabbaabc"};CreateString(S,input);CreateString(T,model);printf("index at %d in %s\n",Index(S,T,0),input);printf("index_KMP at %d in %s\n",Index_KMP(S,T,0),input);Sleep(3000);Dynamic_next(T);printf("\n");return 0;}</span><span style="font-size:24px;"></span>

传统算法核心:

<span style="font-size:14px;">while(i<=S[0] && j<=T[0]){if(S[i] == T[j]){++i;++j;}else{i = i-j+2;j=1;}}</span>

kmp算法核心:

<span style="font-size:14px;">while(i<=S[0] && j<=T[0]){if(S[i] == T[j] || j==0){++i;++j;}else{j = next[j];}}</span>

算法难点——求next和nextval值:

<span style="font-size:14px;">while(i<T[0]){if(T[i] == T[j] || j==0){++i;++j;next[i] = j;}else{j = next[j];}}while(i<T[0]){if(T[i] == T[j] || j==0){++i;++i;if(T[i]!=T[j])nextval[i] = j;elsenextval[i] = nextval[j];}else{j = nextval[j];}}</span>


总结:

在求模式串的next值时,
1.若T[i]与T[j]匹配:则T[j+1]的next = T[j]的next+1;
2.若T[i]与T[j]失配:则T[j]要和T[next[j]]匹配,即j = next[j];
3.若一直匹配失败到j=0,则T[j+1]的next = 1;
故是通过T[j]来推出T[j+1]的next值。

0 0
原创粉丝点击