串的模式匹配
(1)、Brute-Force
暴风(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。
如目标串:"caatcat",t="cat",pos=1,匹配过程如图

程序如下:
#include<stdio.h>
#include<stdlib.h>
#define MAXNUM 100
//顺序串的存储结构,即串中的字符被依次存放在一组连续的存储单元中
typedef struct St
{
char *ch; //存放串的起始地址,串中的第i个元素存储在ch[i-1]中
int length; //串的长度
int strsize;//分配给串的存储空间大小,若不够,通过realloc()再分配,增加存储空间
}String;
String CreateNullString()
{
String s;
s.ch=(char *)malloc(MAXNUM*sizeof(char)); //初始化串的存储空间
s.length=0;
s.strsize=MAXNUM;
return s;
}
//为字符串赋值
void Stringassign(String *s,char s2[])
{
int i=0;
//统计串s2的长度,若不够,然后再通过realloc去增加存储空间
while(s2[i]!='\0')
i++;
if(i>s->strsize)
{
s->ch=(char *)realloc(s->ch,i*sizeof(char));
s->strsize=i;
}
s->length=i;
for(i=0;i<s->length;i++)
s->ch[i]=s2[i];
}
/*
s:目标字符串
t:匹配字符串
pos:索引
*/
int index(String s,String t,int pos)
{
int i,j;
if(pos<1 || s.length<pos || s.length-t.length+1<pos)
{
printf("输入参数不合理\n");
exit(0);
}
i=pos-1;
j=0;
while(i<s.length && j<t.length)
{
if(s.ch[i]==t.ch[j])
{
i++; //第i个字符相等,继续匹配
j++;
}
else
{
i=i-j+1; //匹配失败,初始i的后一个位置继续开始匹配
j=0;
}
}
if(j>=t.length)
return i-t.length+1; //匹配成功,返回第匹配成功的字符串的起始地址
else
return 0; //未匹配成功
}
void main()
{
String s,t;
int i;
char ch[MAXNUM];
s=CreateNullString();
t=CreateNullString();
printf("请输入主字符串:");
gets(ch);
Stringassign(&s,ch);
printf("输入子串:");
gets(ch);
Stringassign(&t,ch);
printf("输入匹配的起始地址:");
scanf("%d",&i);
i=index(s,t,i);
printf("%d\n",i);
}
运行结果如下:

备注:关于get()和scanf()函数的区别
gets() : gets从标准输入设备读字符串函数。可以无限读取,不会判断上限,以回车结束读取,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。(从stdio流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中。换行符不作为读取串的内容,读取的换行符被转换为‘\0’空字符,并由此来结束字符串。)
scanf() :它是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中。(从标准输入流stdio (标准输入设备,一般指向键盘)中读内容的通用子程序,可以说明的格式读入多个字符,并保存在对应地址的变量中。)
总结:
scanf( )函数和gets( )函数都可用于输入字符串,但在功能上有区别,gets可以接收空格;而scanf遇到空格、回车和Tab键都会认为输入结束,所以它不能接收空格。
1.scanf()
所在头文件:stdio.h
语法:scanf("格式控制字符串",变量地址列表);
接受字符串时:scanf("%s",字符数组名或指针);
2.gets()
所在头文件:stdio.h
语法:gets(字符数组名或指针);
3、两者在接受字符串时:
1.不同点:
scanf不能接受空格、制表符Tab、回车等;
而gets能够接受空格、制表符Tab和回车等;
2.相同点:
字符串接受结束后自动加'\0'。
(2)、KMP算法
最主要的是求模式串的next数组,以字符串str=“ababaaababaa”为例,求解过程如下:
| 下标 i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 对应字符 | a | b | a | b | a | a | a | b | a | b | a | a |
| next[i] | -1 | 0 | 0 | 1 | 2 | 3 | 1 | 1 | 2 | 3 | 4 | 5 |
对于上述求解next的过程如下,首先,初始化next[0]=-1,next[1]=0;
当i=2时,比较str[i-1]==str[next[i-1]]。即str[1]=b,str[next[2-1]]=str[0]=a,两者不相等,此时匹配的next已经在无法再向前推了,就取next[2]=0;
当i=3时,比较str[i-1]==str[next[i-1]]。即str[2]=a,str[next[3-1]]=str[0]=a,此时两者相等,则next[i]=next[i]+1,即next[3]=next[2]+1=1;
当i=4时,比较str[i-1]==str[next[i-1]]。即str[3]=b,str[next[4-1]]=str[1]=b,此时两者相等,则next[i]=next[i]+1,即next[3]=next[3]+1=1;
...
当i=6时,比较str[i-1]==str[next[i-1]]。即str[5]=a,str[next[6-1]]=str[3]=b,此时两者不相等,就继续根据next数组往前查找,求解str[next[next[6-1]]]=str[next[3]]=str[1]=b,此时仍不相等,再继续往前查找,直到查找到next[0]为止,若还不相等,则另next[i]=0;此处,继续查找时str[next[next[next[6-1]]]]=str[next[next[3]]]=str[next[1]]=str[0]=a,此时相等,就会以最后一步匹配的next值为标准进行加1,将值赋予next[i],即str[next[1]]==str[6-1],所以next[i]=next[1]+1=1;
....(后面以此类推)
示例程序:
输入
第一行一个整数N,表示测试数据组数。
接下来的N*2行,每两行表示一个测试数据。在每一个测试数据中,第一行为模式串,由不超过10^4个大写字母组成,第二行为原串,由不超过10^6个大写字母组成。
其中N<=20
输出
对于每一个测试数据,按照它们在输入中出现的顺序输出一行Ans,表示模式串在原串中出现的次数。
样例输入:
5 HA HAHAHA WQN WQN ADA ADADADA BABABB BABABABABABABABABB DAD ADDAADAADDAAADAAD
样例输出:
3 1 3 1 0
代码如下:
#include <iostream>
using namespace std;
void getNext(const string &str,int *next){
next[0] = -1;
int j = 0, k = -1;
while(j < str.length()){
if( k == -1 || str[j] == str[k] ){
next[++j] = ++k;
}else{
k = next[k];
}
}
}
int KMP(const string &str1,const string &str2,int next[]){
int i=0, j=0,count=0;
while(i < str1.length()){
int len = str2.length();
while(j < len && i < str1.length() ){
if(j == -1 || str1[i] == str2[j]){
i++;
j++;
}else{
j=next[j];
}
}
if(j == str2.length()){
count++;
j=next[j];
}
}
return count;
}
int main(){
int n;
while(scanf("%d",&n) != EOF){
int word=0;
while(word<n){
string s1,s2;
cin>>s1;
cin>>s2;
int next[s1.length()]={0},count=0;
getNext(s1,next);
for (int i = 0; i < s1.length(); ++i) {
cout<<next[i]<<" ";
}
cout<<endl;
count=KMP(s2,s1,next);
cout<<count<<endl;
word++;
}
}
return 0;
}

浙公网安备 33010602011771号