导航:首页 > 源码编译 > ckmp匹配算法

ckmp匹配算法

发布时间:2022-09-25 02:52:51

‘壹’ 急!!急!!急!!数据结构(C语言版)程序设计题: 使用KMP算法实现一个模式匹配。

#include <cstring>

#include <iostream>

using namespace std;

//修正后的求next数组各值的函数代码

void get_nextval(char const* ptrn, int plen, int* nextval)

{

int i = 0; //i是从0开始的

nextval[i] = -1;

int j = -1;

while( i < plen-1 )

{

if( j == -1 || ptrn[i] == ptrn[j] ) //循环的if部分

{

++i;

++j;

if( ptrn[i] != ptrn[j] ) //++i,++j之后,再次判断ptrn[i]与ptrn[j]的关系

nextval[i] = j;

else

nextval[i] = nextval[j];

}

else //循环的else部分

j = nextval[j];

}

}

void print_progress(char const* src, int src_index, char const* pstr, int pstr_index)

{

cout<<src_index<<"\t"<<src<<endl;

cout<<pstr_index<<"\t";

for( int i = 0; i < src_index-pstr_index; ++i )

cout<<" ";

cout<<pstr<<endl;

cout<<endl;

}

//int kmp_seach(char const*, int, char const*, int, int const*, int pos) KMP模式匹配函数

//输入:src, slen主串

//输入:patn, plen模式串

//输入:nextval KMP算法中的next函数值数组

int kmp_search(char const* src, int slen, char const* patn, int plen, int const* nextval, int pos)

{

int i = pos;

int j = 0;

while ( i < slen && j < plen )

{

if( j == -1 || src[i] == patn[j] )

{

++i;

++j;

}

else

{

j = nextval[j];

//当匹配失败的时候直接用p[j_next]与s[i]比较,

//下面阐述怎么求这个值,即匹配失效后下一次匹配的位置

}

}

if( j >= plen )

return i-plen;

else

return -1;

}

int main()

{

std::string src = "";

std::string prn = "abac";

int* nextval = new int[prn.size()];

//int* next = new int[prn.size()];

get_nextval(prn.data(), prn.size(), nextval);

//get_next(prn.data(), prn.size(), next);

for( int i = 0; i < prn.size(); ++i )

cout<<nextval[i]<<"\t";

cout<<endl;

cout<<"result sub str: "<<src.substr( kmp_search(src.data(), src.size(), prn.data(), prn.size(), nextval, 0) )<<endl;

system("pause");

delete[] nextval;

return 0;

}
望楼主采纳!

‘贰’ kmp 算法原理

朴素算法
先看看最“朴素”的算法: ///find a template in a string. #include<string.h> #include<stdio.h> int Index(char *S, char *T, int pos) { int k=pos, j=0; while(k <strlen(S) && j<strlen(T))//未超出字符串的长度 { if (S[k] == T[j]) { ++k; ++j;} //如果相同,则继续向后比较 else {k = k-j+1; j =0;} //如果不同,就回溯,重新查找 } if (j == strlen(T)) return k-strlen(T); else return 0; }
编辑本段KMP算法
一种由Knuth(D.E.Knuth)、Morris(J.H.Morris)和Pratt(V.R.Pratt)三人设计的线性时间字符串匹配算法。这个算法不用计算变迁函数δ,匹配时间为Θ(n),只用到辅助函数π[1,m],它是在Θ(m)时间内,根据模式预先计算出来的。数组π使得我们可以按需要,“现场”有效的计算(在平摊意义上来说)变迁函数δ。粗略地说,对任意状态q=0,1,…,m和任意字符a∈Σ,π[q]的值包含了与a无关但在计算δ(q,a)时需要的信息。由于数组π只有m个元素,而δ有Θ(m∣Σ∣)个值,所以通过预先计算π而不是δ,使得时间减少了一个Σ因子。[1] KMP算法是通过分析子串,预先计算每个位置发生不匹配的时候,所需GOTO的下一个比较位置,整理出来一个next数组,然后在上面的算法中使用。
编辑本段KMP算法的讲解
当我们分析一个子串时,例如:abcabcddes. 需要分析一下,每个字符x前面最多有多少个连续的字符和字符串从初始位置开始的字符匹配。然后+1就行了(别忘了,我们的字符串都是从索引1开始的)当然,不要相同位置自己匹配,默认第一个字符的匹配数是0。
编辑本段定义
设字符串为 x1x2x3...xn ,其中x1,x2,x3,... xi,... xn均是字符,设ai为字符xi对应的整数。则a=m,当且仅当满足如下条件:字符串x1x2...xm equals 字符串x(i-m+1)...xi-1 xi 并且x1x2...xm x(m+1) unequals x(i-m) x(i-m+1)...xi-1 xi。
编辑本段举例
abcabcddes 0111234111 |----------------------默认是0 --| | |-----------------不能自己在相同位置进行字符匹配,所以这里认为没有匹配字符串,所以0+1 =1,继续从1开始匹配 ------| | |-----------前面的字符和开始位置的字符相同,所以是2,3,4 -----------| | | |-------不匹配只能取1。 希望能明白的是,如果开始字符是 Ch1的话,那么我们就是要在串中第2个Ch1后面的位置开始自己和自己匹配,计算最大的吻合度。 程序写出来就是: void GetNext(char* T, int *next) { int k=1,j=0; next[1]=0; while( k〈 T[0] ){ if (j ==0 || T[k] == T[j]) { ++k; ++j; next[k] = j; } else j= next[j]; } } 但是这个不是最优的,因为他没有考虑aaaaaaaaaaaaaaaaaaab的情况,这样前面会出现大量的1,这样的算法复杂度已经和最初的朴素算法没有区别了。所以稍微改动一下: void GetNextEx(char *T, char *next) { int k=1,j=0; next[1] = 0; while(k < T[0]) { if (j == 0 || T[k] == T[j]) { ++k; ++j; if (T[k] == T[j]) next[k] = next[j]; else next[k] = j; } else j = next[j]; } } 现在我们已经可以得到这个next字符串的值了,接下来就是KMP算法的本体了: 相当简单: int KMP(char* S, char* T, int pos) { int k=pos, j=1; while (k){ if (S[k] == T[j]){ ++k; ++j; } else j = next[j]; } if (j>T[0]) return k-T[0]; else return 0; } 和朴素算法相比,只是修改一句话而已,但是算法复杂度从O(m*n) 变成了:O(m)
编辑本段KMP算法的伪代码
KMP-MATCHER(T,P) 1n ← length[T] 2m ←length[P] 3π ← COMPUTE-PREFIX-FUNCTION(P) 4q ← 0△Number of characters matched. 5for i ← 1 to n△Scan the text from left to right. 6do while q>0 and P[q+1]≠T[i] 7do q ← π[q]△Next character does not match. 8if P[q+1]=T[i] 9then q ← q+1△Next character matches. 10if q=m△Is all of P matched? 11then print “Pattern occurs with shift” i-m 12q ← π[q]△Look for the next match. COMPUTE-PERFIX-FUNCTION(P) 1m ← length[P] 2π[1] ← 0 3k ← 0 4for q ← 2 to m 5do while k>0 and P[k+1]≠P[q] 6do k ← π[k] 7if P[k+1]=P[q] 8then k ← k+1 9π[q] ← k 10return π[1]
编辑本段KMP算法的c++实现
//c++实现的KMP算法,所有涉及字符串,其初始下标从0开始(上述算法均是从1开始) //example: char s[100],t[100];cin>>s>>t;KMP(s,t); //获取待查询模式的next数组 int* get_next(char* T, int* next){ int i = 0, j = -1; int length = strlen(T); int *temp = next; *next = -1; while(i< length){ if(j==-1 || *(T+i)==*(T+j)){ i++; j++; //优化后的get_next方法,可以防止出现形如"aaaaab"这种模式的计算退化 if(*(T+i)!=*(T+j)) *(next+i)=j; else *(next+i)=*(next+j); } else j=*(next+j); } return temp; } //KMP算法 int KMP(char *S, char *T){ int S_Length = strlen(S); int T_Length = strlen(T); //若模式长度大于字符串,则直接返回查询失败 if( S_Length < T_Length) return 0; int i = 0, j = 0; int* next = new int[T_Length]; get_next(T, next); while(i < S_Length && j < T_Length){ if(j == -1 || *(S+i) == *(T+j)){ i++; j++; } else j=*(next+j); } if(j>=T_Length) return i-T_Length; return 0; } 在此提供一个更简明的适用于字符串的kmp实现: #include<iostream> #include<string.h> int next[100]; void getnext(char b[]) { int i=1,j=0; //i是每个位子,j是回退的位子 next[1]=0; while(i<=strlen(b)) { if(j==0||b[i-1]==b[j-1]) { i++; j++; next[i]=j; } else j=next[j]; //用上一个的 回退关系 } } int kmp(char a[],char b[]) { int i=1,j=1; //i是主串中的位子 ,j匹配串的位子 while(i<=strlen(a)&&j<=strlen(b)) { if(j==0||a[i-1]==b[j-1]) { i++; j++; } else j=next[j]; } if(j>strlen(b)) return i-strlen(b); else return 0; } int main() { char a[40],b[40]; printf("要匹配的主串:\n"); scanf("%s",a); printf("要匹配的子串:\n"); scanf("%s",b); getnext(b); printf("输出next值:\n"); for(int i=1;i<=strlen(b);i++) printf("%d ",next[i]); printf("\n"); printf("%d",kmp(a,b)); system("pause"); main(); return 0; }
编辑本段串的最大匹配算法
摘要:
给定两个串S和T,长分别m和n,本文给出了一个找出二串间最大匹配的算法。该算法可用于比较两个串S和T的相似程度,它与串的模式匹配有别。
关键词:
模式匹配 串的最大匹配 算法 Algorithm on Maximal Matching of Strings Lin YuCai Xiang YongHong Zhang ChunXia Zhang JianJun (Computer Science Department of Yunnan Normal University Kunming 650092) ABSTRACT Given Two Strings S of length m and T of length n,the paper presents an algorithm which finds the maximal matching of them. The algorithm can be used to compare the similarility of the two strings S and T, it is different with the strings' pattren matching. KEY WORDS Pattern Matching Maximal Matching of Strings Algorithm
编辑本段问题的提出
字符串的模式匹配主要用于文本处理,例如文本编辑。文本数据的存储(文本压缩)和数据检索系统。所谓字符串的模式匹配[2],就是给定两个字符串S和T,长度分别为m和n,找出T中出现的一个或多个或所有的S,在这方面已经取得了不少进展[3][4][5][6][7][8][9][10][11]。本文从文本处理的另一个角度出发,找出两个串的最大匹配,比较其相似程度[1]。它主要应用于文本比较,特别是在计算机辅助教学中。显然前者要找S的完全匹配,而后者并无此要求。例如,若S=ABCD,T=EFABCDX,那么模式匹配的结果就是找出了T中的一个ABCD,而我们算法的结果就是S能与T的ABCD完全匹配,但是T中还有3个字符是比S多出来的,也就是说在S中有100%的字符与T中的匹配,而在T中有57%的字符与S中的匹配。若S= ABCDFE,T=AFXBECDY。则在模式匹配中S与T无匹配项,但在我们的算法中就能发现T中存在A,B,C,D,但D后不存在E,F。而且S中也存在A,B,C,D,且具有顺序性。这样就能公正地评价S,T的区别。得知其相似程度。 文章的组织如下:首先介绍基本定义和问题的描述;第三节是算法设计;最后是本文总结。
编辑本段问题的描述
设∑为任意有限集,其元称为字符,w:∑→N为∑到N的函数,称为∑的权函数(注:本文仅讨论权值恒为1的情况)。∑*为∑上的有限字符串集合,那么对任意S,T∈∑*,设S=a1a2…am,T=b1b2…bn,m>0,n>0。记<m>={1,2, …,m},<n>={1,2, …,n},则称{(i,j)∣i∈<m>,j∈<n>,ai=bj}为S与T的匹配关系集,记作M(S,T),称M为S与T的一个(容许)匹配,若对任意(i,j), ( i',j' )∈,① i< i',当且仅当j< j',② i= i'当且仅当j= j'。S与T的匹配中满足 最大者,称为S与T的最大匹配。若C(i,j)为N上的m×n矩阵,且满足: 则称矩阵C为串S与T的匹配关系阵。 于是求串S与T的最大匹配,等价于求C中的一个最大独立点集M,它满足,若ci,j,ci',j'∈M,则i< i' 当且仅当j< j',i=i'当且仅当j=j'。我们称这样的最大独立点集为C的最大C-独立点集。 例:设∑为所有字母的集合,对任意x∈∑,w(x)≡1,设S与T分别为:S=“BOOKNEWS”,T=“NEWBOOKS”。则我们可以得到S与T两个匹配: 这里=5; 这里 =4。 显然为串S与T的最大匹配。 S与T的匹配关系阵C可表示如下: 其中带圈的部分为一最大C-独立点集。
编辑本段算法设计
我们仅就权值为一的情况进行讨论。 设S和T为任意给定串,C为的S与T匹配关系阵,那么由2的讨论知,求S与T的最大匹配问题,等价于求C的最大C-独立点集问题。因而,为了解决我们的问题,只要给出求C的最大C-独立点集的算法就可以了。 显然,为了求出C的最大C-独立点集,我们可以采用这样的方法:搜索C的所有C-独立点集,并找出它的最大者。这种方法是可行的,但并不是非常有效的。这会使问题变得很繁,复杂度很大。因此,我们先对问题进行分析。 在下面的讨论中,我们把C的任一C-独立点集={ai1,j1,…,ais,js},记作=ai1,j1…ais,js,i1 <…< is。于是可看作阵C中以1为节点的一条路,满足:对路中的任意两节点,均有某一节点位于另一节点的右下方。称这种路为右下行路。 于是求C-独立点集等价于求阵C的右下行路。这种求右下行路的搜索可以逐行往下进行。 命题1. 若 =αai,jβ和ψ=α'ai,jσ为C的两个C-独立点集,且α为α'的加细,则存在C-独立点集'=αai,jδ,满足≥。 命题2. 若 =αai,jβ和ψ=α'ai+k,jσ为C的两个C-独立点集,且≥,则存在C-独立点集'=αai,jδ,满足≥。 命题3. 若 =αai,jβ和ψ=α'ai,j+kσ为C的两个C-独立点集,且≥,则存在C-独立点集'=αai,jδ,满足≥。 由命题1知,在搜索右下行路的过程中,如果已获得了某一C-独立点集的某一初始截段αai,j和另一C-独立点集ψ的某一初始截段α'ai,j,且有≤,则我们可以停止对ψ的进一步搜索。 由命题2知,在搜索右下行路的过程中,在某一列j存在某两个C-独立点集的某初始截段=ai1,j1…ais,j和ψ=al1,m1…alt,j,如果≥,但lt>is,则我们可以停止对ψ的进一步搜索。 由命题3知,在搜索右下行路的过程中,在某一行i存在某两个C-独立点集的某初始截段=ai1,j1…ai,js和ψ=ai1,m1…ai,mt,如果≥,但mt>js,则我们可以停止对ψ的进一步搜索。 由此可见,并不要求搜索所有C的最大C-独立点集,而可以采用比这简单得多的方法进行计算。那么按照我们上面的三个命题,来看如下实例: 首先我们得到=B(在上的节点用①表示),我们向右下方找路,可以发现,在第4列有两个1,根据命题2,我们选择上面的一个1,也就是说选择第1行的那个1,而不要第2行的那个1。同时我们也发现在第1行也有两个1,由命题3知,我们选择左边的那个1,即第4列的那个1。此时=BO。但是当我们的算法运行到第4行时,=BOOK,由于K在第3行第6列,而本行的1在第1列,在路最后一个节点K的左边,那么我们必须新建一条路ψ,因为我们并不能确定是否以后就有≥,当算法运行到第6行时,=BOOK,ψ=NEW,=4,=3,我们将S链到路上,此时我们得到最长右下行路=BOOKS,=5。这样我们就可以计算出这两个字符串的匹配程度。 在我们的算法设计过程中,用到了两个技巧。技巧之一,矩阵C不用存储,是动态建立的,节省了空间。技巧之二,本算法并不要求所有的S与T中所有的元素都相互进行比较,也并不存储所有的右下行路,节省了时间和空间。由矩阵中1的出现情况可见,本算法所需的空间和时间都远小于O(mn)
编辑本段结束语
本文给出了一个与模式匹配不同的,具有若干应用的,串的最大匹配算法,该算法已经在机器上实现,达到了预期的效果。本文仅讨论权值恒为1的情况,对于权值任意的情形不难由此得到推广。
编辑本段C语言代码(C Code)
#include<stdio.h> #include<string.h> void getnext(int next[],char s[],int l) { int i=1,j=0; next[1]=0; while(i<l) { if(j==0 || s[i]==s[j]) { i++;j++; next[i]=j; } else j=next[j]; } } int KMP(char s1[],char s2[],int l1,int l2,int next[]) { int i,j; i=j=1; while(i<=l1 && j<=l2) { if(j==0||s1[i]==s2[j]) { i++;j++; } else j=next[j]; } if(j>l2) return(i-l2); return 0; } int main() { int next[10001],ans; char s1[10001],s2[10001],l1,l2; scanf("%s",s1+1); scanf("%s",s2+1); l1=strlen(s1+1); l2=strlen(s2+1); getnext(next,s2,l2); ans=KMP(s1,s2,l1,l2,next); if(ans!=0) printf("%d\n",ans); else printf("No!\n"); system("pause"); return 0; }
编辑本段KMP算法的pascal实现
var next:array [1 ..1000001] of longint; s,t:ansistring; procere get_next(t:ansistring); var j,k:integer; begin j:=1; k:=0; while j<length(t) do begin if (k=0) or (t[j]=t[k]) then begin inc(j); inc(k); next[j]:=k; end else k:=next[k]; end; end; function index(s:ansistring;t:ansistring):longint; var i,j:longint; begin get_next(t); index:=0; i:=1; j:=1; while (i<=length(s))and(j<=length(t)) do begin if (j=0)or(s[i]=t[j]) then begin inc(i); inc(j); end else j:=next[j]; if j>length(t) then index:=i-length(t); end; end; begin readln(s); readln(t); writeln(index(s,t)) end.
编辑本段KMP播放器
K-multimedia player的缩写
来自韩国的影音全能播放器,与Mplayer一样从linux平台移植而来的Kmplayer(简称KMP)几乎可以播放您系统上所有的影音文件。通过各种插件扩展KMP可以支持层出不穷的新格式。强大的插件功能,直接从Winamp继承的插件功能,能够直接使用winamp的音频 ,输入,视觉效果插件,而通过独有的扩展能力,只要你喜欢,可以选择使用不同解码器对各种格式进行解码。 KMPlayer The Professional Media Player! 它支持 Winamp 2/5 的输入、常规、DSP、视觉效果、媒体库插件。无须注册表支持直接调用 Directshow 滤镜!FFdshow 的视觉特效系统~超强的 GUI 界面~安装电视卡后可以直接代替原软件直接收看电视~支持播放 DVD/VCD 以及绝大多数电脑的媒体文件(AVI 支持 Xvid/DivX/3vid/H264 OGG/OGM/MKV 容器/AC3/DTS 解码~Monkey Audio 解码~)强烈推荐!此播放器除了会将自己的配置信息写入注册表外绝对绿色~ KMplayer内置目前常见的所有解码器,包括real,QT等。 另外KMplayer安装版也是目前很少见的检查流氓软件的安装方式,如果一旦有恶意的汉化小组汉化并捆绑了流氓软件。该安装程序自动会识别,并作出提示,建议用户不要安装,虽然不是特别准确,但KMplayer的无广告及第三方插件的特点使其深受好评。 目前韩国官方已经在Kmplayer里自带了中文字库,只要用户是中文系统,软件就会自动识别,十分方便。 KMP版本: KMPlayer3.0.0.1439

‘叁’ KMP算法的原理及其应用

KMP算法是通过分析子串,预先计算每个位置发生不匹配的时候,所需GOTO的下一个比较位置,整理出来一个next数组,然后再上面的算法中使用。
讲解一下:
当我们分析一个子串时,例如:abcabcddes. 需要分析一下,每个字符x前面最多有多少个连续的字符和字符串从初始位置开始的字符匹配。然后+1就行了(别忘了,我们的字符串都是从索引1开始的)当然,不要相同位置自己匹配,默认第一个字符的匹配数是0。
定义如下:设字符串为 x1x2x3...xn ,其中x1,x2,x3,... xi,... xn均是字符,设ai为字符xi对应的整数。则a=m,当且仅当满足如下条件:字符串x1x2...xm equals 字符串x(i-m+1)...xi-1 xi 并且x1x2...xm x(m+1) unequals x(i-m) x(i-m+1)...xi-1 xi。
举例如下:
abcabcddes
0111234111
|----------------------默认是0
--| | |-----------------不能自己相同字符匹配,所以这里者能认为是没有所以是0+1 =1
------| | |-----------前面的字符和开始位置的字符相同,所以是2,3,4
-----------| | | |-------不匹配只能取1。
希望能明白的是,如果开始字符是 Ch1的话,那么我们就是要在串中第2个Ch1后面的位置开始自己和自己匹配,计算最大的吻合度。
程序写出来就是:
void GetNext(char* T, int *next)
{
int k=1,j=0;
next[1]=0;
while( k〈 T[0] ){
if (j ==0 || T[k] == T[j])
{
++k;
++j;
next[k] = j;
}
else j= next[j];
}
}
但是这个不是最优的,因为他没有考虑aaaaaaaaaaaaaaaaaaab的情况,这样前面会出现大量的1,这样的算法复杂度已经和最初的朴素算法没有区别了。所以稍微改动一下:
void GetNextEx(char *T, char *next)
{
int i=k,j=0; next[1] = 0;
while(k < T[0])
{
if (j == 0 || T[k] == T[j])
{
++k; ++j;
if (T[k] == T[j])
next[k] = next[j];
else
next[k] = j;
}
else j = next[j];
}
}
现在我们已经可以得到这个next字符串的值了,接下来就是KMP算法的本体了:
相当简单:
int KMP(char* S, char* T, int pos)
{
int k=pos, j=1;
while (k){
if (S[k] == T[j]){ ++k; ++j; }
else j = next[j]
}
if (j>T[0]) return k-T[0];
else return 0;
}
和朴素算法相比,只是修改一句话而已,但是算法复杂度从O(m*n) 变成了:O(m)

‘肆’ 解析一哈c语言中的kmp算法,bf算法,kr算法之间的联系与区别,尽量浅显易懂,谢谢!

三种算法联系:都是字符串匹配算法。
区别:
“KMP算法”:在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=-1,则将i右移1位,并将j置0,继续进行比较。
“BF算法”是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串P的第一个字符进行匹配,若相等,则继续比较S的第二个字符和P的第二个字符;若不相等,则比较S的第二个字符和P的第一个字符,依次比较下去,直到得出最后的匹配结果。
“KR算法”在每次比较时,用HASH算法计算文本串和模式串的HASH映射,通过比较映射值的大小来比较字符串是否匹配。但是考虑到HASH冲突,所以在映射值相同的时候,还需要近一步比较字符串是否相同。但是在每次比较时,需要计算HASH值,所以选择合适的HASH算法很重要。
略知一二!

‘伍’ 请会编程的同学帮忙用c语言写一个无回溯模式匹配,kmp算法。。

KMP算法查找串S中含串P的个数count #include <iostream> #include <stdlib.h> #include <vector> using namespace std; inline void NEXT(const string& T,vector<int>& next) { //按模式串生成vector,next(T.size()) next[0]=-1; for(int i=1;i<T.size();i++ ){ int j=next[i-1]; while(T[i]!=T[j+1]&& j>=0 ) j=next[j] ; //递推计算 if(T[i]==T[j+1])next[i]=j+1; else next[i]=0; // } } inline string::size_type COUNT_KMP(const string& S, const string& T) { //利用模式串T的next函数求T在主串S中的个数count的KMP算法 //其中T非空, vector<int> next(T.size()); NEXT(T,next); string::size_type index,count=0; for(index=0;index<S.size();++index){ int pos=0; string::size_type iter=index; while(pos<T.size() && iter<S.size()){ if(S[iter]==T[pos]){ ++iter;++pos; } else{ if(pos==0)++iter; else pos=next[pos-1]+1; } }//while end if(pos==T.size()&&(iter-index)==T.size())++count; } //for end return count; } int main(int argc, char *argv[]) { string S=""; string T="ab"; string::size_type count=COUNT_KMP(S,T); cout<<count<<endl; system("PAUSE"); return 0; } 补上个Pascal的KMP算法源码 PROGRAM Impl_KMP; USES CRT; CONST MAX_STRLEN = 255; VAR next : array [ 1 .. MAX_STRLEN ] of integer; str_s, str_t : string; int_i : integer; Procere get_nexst( t : string ); Var j, k : integer; Begin j := 1; k := 0; while j < Length(t) do begin if ( k = 0 ) or ( t[j] = t[k] ) then begin j := j + 1; k := k + 1; next[j] := k; end else k := next[k]; end; End; Function index( s : string; t : string ) : integer; Var i, j : integer; Begin get_next(t); index := 0; i := 1; j := 1; while ( i <= Length(s) ) and ( j <= Length(t) ) do begin if ( j = 0 ) or ( s[i]= t[j] ) then begin i := i + 1; j := j + 1; end else j := next[j]; if j > Length(t) then index := i - Length(t); end; End; BEGIN ClrScr;{清屏,可不要} Write(‘s = ’); Readln(str_s); Write(‘t = ’); Readln(str_t); int_i := index( str_s, str_t ); if int_i <> 0 then begin Writeln( 'Found' , str_t,' in ', str_s, 'at ', int_i,' .' ); end else Writeln( 'Cannot find ', str_t,' in' , str_s, '. '); END.

‘陆’ C语言的KMP 匹配算法,VS老是报错,不知道是不是编译器的问题,请高手赐教啊!!!

//#include<iostream> //这一行是C++标准库,C语言编程时不需要
#include<stdio.h>
#include<string.h> //C语言字符串处理头文件是 string.h 而不是 string
//using namespace std; //这一行是C++标准命名空间的声明,C语言编程时不需要
#define MAXSTRLEN 255

typedef unsigned char SString[MAXSTRLEN+1];

//计算最大滑动距离
void getnext(SString t,int next[])
{
int i,j;

////////////////////////////////////////////////////////////////////////////经典的KMP算法
i=0, j=-1; // 此处最好是分为两条语句,而不是写在一起,这也是编程风格问题
next[0] = -1;
while(i<t[0])
{
if(j==-1 || (j>=0 && t[i]==t[j]))
{
i++;
j++;
next[i]=j;
}
else
j=next[j];
}
}
//*
//模式匹配,返回最小匹配的位置
int kmp(SString s, SString t,int next[])
{
int i = 0, j = 0;

while(i<s[0]&&j<t[0])
{
if(j==-1||s[i]==t[j])
{
++i,++j;
}
else j = next[j];
}
if(j>=t[0])
return i-t[0];
else return -1;
}
/////*/
int main()
{
int next[MAXSTRLEN];
SString s,t;
memset(s,0,sizeof(s));//对较大的数组进行初始化,有利于程序的多组数据测试,本例中只执行一
memset(t,0,sizeof(t)); //次程序,可暂时不需要,但是初始化以后更好,这个也属于编程风格问题
printf("please input a main string\n");
scanf("%s",s); // 楼主在此处应该小心,输入格式控制是 %s 而不是 s%
printf("please input a sub string\n");
scanf("%s",t); // 同上
getnext(t,next);
kmp(s,t,next);
return 0;
}
/****
//最后 此程序没有输出,不能看出来所需要的结果,因此不实用;不过前提要保证算法正确,我
//没有时间去验证你的这个KMP算法是否正确,你自己再多去调试一下。
//另外就是,楼主最好注意编程风格问题,好的编程风格增强代码的可读性,也方便调试;这个最
//好是从一开始就坚持下去,久而久之你就会发现其中的好处了。
*****/

‘柒’ 算法基础 - 朴素模式匹配算法、KMP模式匹配算法

假设我们要从 主字符串goodgoogle 中匹配 子字符串google
朴素模式匹配算法就是 通过从主字符的头部开始 一次循环匹配的字符串的挨个字符 如果不通过 则主字符串头部位置遍历位置+1 在依次遍历子字符串的字符

匹配过程
主字符串从第一位开始 取出g 子字符串取出第一位 g 匹配 进入子循环
取出o 取出o 匹配
取出o 取出o 匹配
取出d 取出g 不匹配 主字符串遍历位置+1

主字符串从第二位开始 取出o 子字符串取出第一位 g 不匹配 主字符串遍历位置+1

主字符串从第三位开始 取出o 子字符串取出第一位 g 不匹配 主字符串遍历位置+1

主字符串从第四位开始 取出d 子字符串取出第一位 g 不匹配 主字符串遍历位置+1

主字符串从第五位开始 取出g 子字符串取出第一位 g 匹配 进入子循环
取出o 取出o 匹配
取出o 取出o 匹配
取出g 取出g 匹配
取出l 取出l 匹配
取出e 取出e 匹配 子循环结束 匹配成功

假设主字符串 长度为 n 子字符串长度为m n>= m
最好的情况需要匹配m次 时间复杂度为 0(m)

例如 000000000001 匹配 00001 每次进入子循环之后 都要遍历到最后一次子循环才得出不匹配
需要匹配次数 (n-m+1) * m
最坏的情况需要匹配m次 时间复杂度为 0((n-m+1) * m)

KMP 算法的主要核心就是 子字符串在子循环内得出不匹配时 主字符串当前的判断位不需要回溯–也就是不可以变小 ,且子循环的判断位需要回溯 回溯位与子字符串本身是否具有重复结构有关 。 以此来规避无效的判断
时间复杂度为 O(n+m)

如果主串 S = "abcdefgab" 我们要匹配的子串 T = "abcdex" 如果用前面的朴素算法 , 前5个字母完全相同
直到第6个字母 f 和 x 不同
步骤1
S: a b c d e f g a b
T: a b c d e x

接下来如果用朴素算法的话 那么应该是如下比较
步骤2
S: a b c d e f g a b
T: # a b c d e x
b 和 a 不匹配

步骤3
S: a b c d e f g a b
T: # # a b c d e x
a和c 不匹配

步骤4
S: a b c d e f g a b
T: # # # # a b c d e x
d和a 不匹配

步骤5
S: a b c d e f g a b
T: # # # # a b c d e x
a和e 不匹配

步骤6
S: a b c d e f g a b
T: # # # # # a b c d e x

即主串S中的第2 ,3 , 4, 5, 6 位都与子串T的首字符不相等

对于子串T来说 如果首字符a与后面的bcdex中任意一个字符都不相等
那么对于上面的第一步来说 前五位都相等 那么 可以得到 子串首字符a 与主串的第2,3,4,5 位都不相等
即步骤2 , 3 ,4 ,5 都是多余的 可以直接进入步骤6

如果子串的首字符串与后面的字符有相等的情况
假设S = "abcababca" T= "abcabx"

朴素算法
步骤1
S: a b c a b a b c a
T: a b c a b x
a 与 x 不匹配

步骤2
S: a b c a b a b c a
T: # a b c a b x
b 与 a 不匹配

步骤3
S: a b c a b a b c a
T: # # a b c a b x
c 与 a 不匹配

步骤4
S: a b c a b a b c a
T: # # # a b c a b x
a 与 a 匹配

步骤5
S: a b c a b a b c a
T: # # # # a b c a b x
b 与 b 匹配

步骤6
S: a b c a b a b c a
T: # # # # a b c a b x
a 与 c 不匹配

因为步骤1 中已经得出 前五位已经完全匹配 并且子串首字符ab 存在相同的情况 所以 步骤2,3 是多余的

直接进入步骤4 因为步骤1中已经得出 主串与子串前五位相同 同时 子串1 2 位与 子串的4 5 位相同 所以可得出
子串1 2 位 与当前主串匹配位置开始的前两位也就是主串的4 5 位匹配 所以步骤4 , 5 是多余的 可以直接进入步骤6

通过上面的两个例子我们可以发现 主串的比较位是不会回溯的 , 而子串的比较位与子串本身结构中是否有重复相关

子串不重复 举例
S: a b c d e f g a
T: a b c d e x

子串第6位不匹配 且本身没有重复 那么下一次循环 就变成了 子串的第一位与主串的第二位比较
即子串的匹配位从6 变成了1

S: a b c d e f g a
T: # a b c d e x

子串重复 举例
S: a b c a b a b c a
T: a b c a b x
a 与 x 不匹配

子串在第六位发生不匹配是 前五位abcab 具有重复结构 ab 所以子串匹配位发生变化 即子串的匹配位从6 变成了 3

S: a b c a b a b c a
T: # # # a b c a b x
a 与 c 不匹配

我们可以得出 子串匹配位的值 与主串无关 只取决于当前字符串之前的串前后缀的相似度
也就是说 我们在查找字符前 ,要先对子串做一个分析 获取各个位置不匹配时 下一步子串的匹配位

前缀 : 从头开始数 不包含最后一位
后缀 : 不是倒着数 是以和前缀相同的字符串为结尾的部分
例如 字符串 a 没有前后缀
字符串 ab 没有前后缀
字符串 aba 没有前后缀
字符串 abab 前后缀 ab
字符串 ababa 前后缀 可以是 a 可以是 aba 我们取长度最长的 即 aba

第一位时 next值固定为0
其他情况 取其公共最长前后缀的长度+1 没有则为1

因为一共子串有8位 所以在子循环内一共需要获取 8次前后缀
这里我们定义一个next数组 长度为8 里面的元素分别对应子串各个子循环内的 前后缀长度
第1位不匹配时 获取字符串为a 没有前字符串 没有前后缀 那么next[1] = 0
第2位不匹配时 获取字符串为ab 有前字符串a 没有前后缀 那么next[2] = 1
第3位不匹配时 获取字符串为aba 有前字符串ab 没有前后缀 那么next[3] = 1
第4位不匹配时 获取字符串为abab 有前字符串aba 前后缀 a 那么next[4] = 2
第5位不匹配时 获取字符串为ababa 有前字符串abab 前后缀 ab 那么next[5] = 3
第6位不匹配时 获取字符串为ababaa 有前字符串ababa 前后缀 aba 那么next[6] = 4
第7位不匹配时 获取字符串为ababaab 有前字符串ababaa 前后缀 a 那么next[7] = 2
第8位不匹配时 获取字符串为ababaabc 有前字符串ababaab 前后缀 ab 那么next[8] = 3

next数组为[ 0, 1 , 1 ,2 , 3, 4 ,2, 3 ]

后来有人发现 KMP还是有缺陷的 比如 当子串 T = "aaaaax"
在5位发生不匹配 此时 next[5] = 4 接着就是 子串中的第四位a与 主串当前位置字符比较

因为子串第五位等于子串第四位相同 所以可以得出该步骤也不匹配 此时 next[4] = 3
依然不匹配 直到next[1] = 0

我们可以发现由于T串中的 2 3 4 5 位置都与首位a 相等 中间的过程都是多余的
那么可以用首位的next[1] 的值 去替代与它相等的字符后续的next[x]的值

‘捌’ KMP算法的C语言程序

#include "iostream"
#include "stdlib.h"
#include "stdio.h"
#include "malloc.h"
#define MAXSTRLEN 100
#define OK 1
#define NULL 0
using namespace std;
typedef char SString[MAXSTRLEN+1];
SString T,S;
int next[MAXSTRLEN],c[MAXSTRLEN];
int i,j;
void get_next(SString &T,int next[MAXSTRLEN]){
i=1;next[1]=0;j=0;
while(i<T[0]){
if(j==0||T[i]==T[j]){++i;++j;next[i]=j;}
else j=next[j];
}
}
int KMP(SString &S,SString &T){
i=1;j=1;
while(i<=S[0]&&j<=T[0]){
if(j==0||S[i]==T[j]){++i;++j;}
else j=next[j];
}
if(j>T[0])return i-T[0];
else return 0;
}
void main(){
int k,p=1;
int i=1,j=1;
printf("输入主串:");
gets(&M[1]);
printf("输入模式串:");
gets(&N[1]);
while(M[i]!=NULL)
{
i++;
M[0]=i-1;
}
puts(&M[1]);

while(N[j]!=NULL)
{
j++;
N[0]=j-1;
}
puts(&N[1]);
if(M[0]>N[0])
{
printf("error!");
exit(0);
}
get_next(T,next);
for(i=1;i<=T[0];i++)printf("%d",next[i]);
printf("\n");
k=KMP(S,T);
printf("模式串从主串第%d个开始匹配!",k);
}

‘玖’ 串模式匹配算法(C语言)100分悬赏

第一个朴素算法:
1.普通的串模式匹配算法:
int index(char s[],char t[],int pos)
/*查找并返回模式串T在S中从POS开始的位置下标,若T不是S的子串.则返回-1.*/
{
int i,j,slen,tlen;
i=pos;j=0; //i,j分别指示主串和模式串的位置.
slen=strlen(s);tlen=strlen(t); //计算主串和模式串的长度.
while(i<slen && j<tlen)
{
if(s[i]==t[j]) {i++;j++;}
else {i=i-j+1;j=0;}
}
if(j>=tlen) return i-tlen;
return -1;
}

第二个KMP算法.该算法支持从主串的任意位置开始搜索.
2.KMP算法:
//求模式串的next函数.
void get_next(char *p,int next[])
{
int i,j,slen;
slen=strlen(p);i=0;
next[0]=-1;j=-1;
while(i<slen)
{
if(j==-1||p[i]==p[j]) {++i;++j;next[i]=j;}
else j=next[j];
}
}

//KMP模式匹配算法
int index_kmp(char *s,char *p,int pos,int next[])
/* 利用模式串P的NEXT函数,求P在主串S中从第POS个字符开始的位置*/
/*若匹配成功.则返回模式串在主串中的位置下标.否则返回-1 */
{
int i,j,slen,plen;
i=pos-1;j=-1;
slen=strlen(s);plen=strlen(p);
while(i<slen && j<plen)
{
if(j==-1||s[i]==p[j]) {++i;++j;}
else j=next[j];

阅读全文

与ckmp匹配算法相关的资料

热点内容
企业网搭建及应用pdf 浏览:742
symanteclinux 浏览:876
程序员朋友化妆改造 浏览:491
应用被加密但不知道密码 浏览:586
百度云黑马android 浏览:773
java格式化long 浏览:893
汽车如何加密文档 浏览:625
公司理财第9版pdf 浏览:524
微信个人表情在文件夹 浏览:833
加密狗密码监控 浏览:437
重载发生在编译时 浏览:417
怎么用app买东西 浏览:532
ug后处理多坐标宏命令 浏览:34
性教育pdf 浏览:863
解释方式编译方式名词解释 浏览:851
wrf编译出现module 浏览:616
插入算法最基础代码 浏览:27
powermill和ug编程 浏览:843
vf命令按钮 浏览:283
涂鸦王国app怎么 浏览:37