带*和?的KMP算法的两种实现方式
这两个都是我做助教的那个班的两个同学完成的,觉得她们做得不错,故贴出来共享。
第一个同学的实现:
#include<iostream.h>
#include<string.h>
#include<assert.h>
class String
{
private:
char * str;
int size;
public:
String( char * s );
~String();
int Strlen ( ) { return strlen( this -> str ) ; } //求长度
char & operator [ ] ( int i ) { return str [ i ] ; } //重载下标运算符
};
String::String(char * s)
{
size = strlen(s);
str = new char[size + 1];
assert(str != NULL);
strcpy(str,s);
}
String::~String()
{
delete str;
}
int * Nature(String & P)
{
int len = P.Strlen() ;
assert( len > 0 ) ;
int * N = new int [ len ] ;
assert( N != NULL ) ;
if( P[0] == '*' )
N[ 0 ] = -1 ;
else
N[ 0 ] = 0 ;
int m = 0 ;
int i = 1 ;
while( m < len )
{
while( i < len && P[ i ] != '*')
{
int k = N[ i -1 ] ;
if( P[ i ] == '?' || P[ k+m ] == '?')
N[ i ] = k + 1 ;
else
{
while( k > 0 && P[ i ] != P[ k+m ] && P[ k+m ] != '?')
k = N[ k-1 ] ;
if( P[ i ] == P[ k+m ] || P[ k+m ] == '?')
N[ i ] = k + 1;
else
N[ i ] = 0;
}
i++;
}
while( P[ i ] == '*' )
{
N[ i ] = -1;
i ++ ;
}
m = i;
}
return N ;
}
int KMP( String & Target , String & Pat , int * N , int StartIndex )
{
int i = 0 , count = 0 ;
for( ; i < Pat.Strlen() ; i ++ )
if( Pat[ i ] == '*' )
count ++;
int LastIndex = Target.Strlen() - Pat.Strlen() ;
if( ( LastIndex - StartIndex ) + count < 0 )
return ( -1 ) ;
i = StartIndex ;
int j = 0 ,m = 0 ;
while( N[ j ] == -1 )
{
j ++;
m ++;
}
int n ,k = 0; //n和k 用来记录开始匹配成功的位置
while( i < Target.Strlen() )
{
while( Target[ i ] != Pat[ j ] && Pat[j ] != '?' && j > m )
j = N[ j - 1 ] + m;
if( Pat[j] == Target[i] || Pat[j ] == '?' )
{
k++;
if(k ==1 )
n = i;
j ++ ;
m ++;
}
while( Pat[j] == '*')
{
j++;
m++;
}
if( j == Pat.Strlen() )
{
cout<<"在位置 "<< n <<" 处匹配成功"<<endl;
return n;
}
i ++ ;
}
cout<<"匹配不成功"<<endl;
return -1;
}
void main()
{
String P( "*an*?g?" ) ;
int * N = Nature( P ) ;
for( int i = 0 ; i < P.Strlen() ; i ++ )
cout << N [ i ] << " ";
cout << endl ;
String T( "zhangg xiexzi afasdg");
int a = KMP( T,P,Nature(P),0);
}
第二个同学的实现:
class string
{
public:
string();
string(char *s);
~string();
char* replace(char A, char B);
int* Next( string P);
int KMP_FindPat(string S,string P,int* N,int startindex);
bool print();
protected:
int size;
char* str;
};
#include<iostream.h>
#include<string.h>
//#include<stdlib.h>
#include"String.h"
#include<assert.h>
string::string()
{
size=0;
str=NULL;
}
string::string(char* s)
{
assert(s!=NULL);
str=new char[strlen(s)+1];
assert(str);
strcpy(str,s);
size=strlen(str);
}
//析构函数destructor
string::~string()
{
size=0;
}
char* string:: replace(char A,char B)
{
for(int i=0;i<size;i++)
{
if(str[i]==A)
str[i]=B;
}
return str;
}
bool string::print()
{
for(int i=0;i<size;i++)
{
cout<<str[i];
}
cout<<endl;
return true;
}
int* string::Next( string P)
{
int m =strlen(P.str);
assert(m>0);
int* N=new int [m];
N[0]=0;
assert(N!=0);
for(int i=1;i<m;i++)
{
int k=N[i-1];
while(P.str[i]!=P.str[k]!='?'!='*'&& k!=0 )
{
k=N[k-1];
}
if(P.str [i]==P.str [k]||P.str [k]=='?'||P.str [i]=='?'||P.str [k]=='*'||P.str [i]=='*')
{
N[i]=k+1;
}
else
{
N[i]=0;
}
}
for(int j=0;j<m;j++)
{
cout<<N[j]<<" ";
}
cout<<endl;
cout<<"The length of P :"<<strlen(P.str)<<endl;
return N;
}
int string:: KMP_FindPat(string S,string P,int *N,int StartIndex)
{
//int i;
int m=0;
int j=0;
int LastIndex=strlen(S.str)-strlen(P.str);
if(LastIndex<StartIndex)
{
return (-1);
}
for(int i=StartIndex;i<strlen(S.str);i++)
{
while(S.str[i]!=P.str[j] && j>0 && P.str[j]!='*'&& P.str[j]!='?')
{
j=N[j-1];
}
if( P.str[j]=='*')
{
j=j+1;
while (S.str[i+1]!=P.str[j] && i<strlen(S.str))
{
i++;
m++;
}
if(i==strlen(S.str))
{
return -1;
}
}
if(S.str[i]==P.str[j]||P.str[j]=='?')
{
j++;
}
if(j == strlen(P.str))
{
return (i-j+1-(m-1));
}
}
return (-1);
}
#include"String.h"
#include<iostream.h>
#include<string.h>
void main()
{
int *N;
int n;
//char* P="infinite";
//char* S="infinishinfinfinite";
string P("a*d*f");
string S("sddddasdfhhhjf");
P.print();
S.print();
N=P.Next(P);
n=S.KMP_FindPat (S, P,N,0);
cout<<n<<endl;
/*for(int i=n;i<n+P.strlen();i++)
{
cout<<S.str[i];
}*/
cout<<endl;
}
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名小橋流水(包含链接)。如您有任何疑问或者授权方面的协商,请给我发邮件。