分析逻辑结构
所谓串就是指字符串,在计算机中是一种很常见并且很重要的数据结构,我们平时所处理的文档实际上就是字符串。而对字符串的操作中比较常见的一种就是对一个串中某子串进行定位也就是模式匹配.其中待定位的子串称为模式串
Brute-Force算法的基本思想是:
1.从目标串s 的第一个字符起和模式串t的第一个字符进行比较,若相等,则继续逐个比较后续字符,否则从串s 的第二个字符起再重新和串t进行比较。
2. 依此类推,直至串t 中的每个字符依次和串s的一个连续的字符序列相等,则称模式匹配成功,此时串t的第一个字符在串s 中的位置就是t 在s中的位置,否则模式匹配不成功。
KMP算法的基本思想是:
每当一趟匹配过程中出现字符比较不相等时,不需要回溯i指针,而是利用已经得到的“部分匹配”的结果将模式串向右滑动尽可能远的一段距离后,继续进行比较;即尽量利用已经部分匹配的结果信息,尽量让i不要回溯,加快模式串的滑动速度。
这里我们通常定义一个next[j]数组,j取1~m,m为模式串长度,表示模式串中第j个字符发生不匹配的时候,应从next[j]处的字符开始重新与主串比较。
例如一个模式串: abaabcac,当在第二个位置出现不匹配的时候,说明主串前面一个字符是a,而模式串的前一个字符是a,所以这个时候,就可以从第二个位置开始比较,这里有两种特殊情况:
(1) 模式串中的第一个字符与主串i位置不匹配,应从下一个位置和模式串第一个字符继续比较。
(2) 当模式串中从第一个字符到不匹配的字符的前一个字符,如果不存在前后重合的部分时,则从主串中发生不匹配的字符和模式串第一字符开始比较。
给出C语言描述:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define max 100
typedef struct {
char data[max];
int length;
}sqstring;
void stra(sqstring &s,char cstr[])
//将字符串常量赋给串s,s为引用型参数
{
int i;
for(i=0;cstr[i]!='\0';i++)
s.data [i]=cstr[i];
s.length =i;
}
void dis(sqstring s)//显示串s中的所有元素
{
int i;
if(s.length >0)
{
for(i=0;i<s.length ;i++)
printf("%c",s.data[i]);
printf("\n");
}
}
int index(sqstring s,sqstring t)//BF模式匹配
{
int i=0,j=0,k;
while(i<s.length &&j<t.length )
{
if(s.data[i]==t.data[j])//继续匹配下一个字符
{
i++;//主串和子串依次匹配下一个字符
j++;
}
else//主串和子串指针回溯重新开始下一次匹配
{
i=i-j+1;//主串从下一个位置开始匹配
j=0;//子串从头开始匹配;
}
}
if(j>=t.length )
k=i-t.length ;//返回匹配的第一个字符下标
else
k=-1;
return k;//模式匹配不成功
}
void getnext(sqstring t,int next[])// 由模式串t求出next的值
{
int j,k;
j=0;k=-1;next[0]=-1;
while(j<t.length -1)
{
if(k==-1||t.data[j]==t.data[k])// k为-1或比较的字符相等
{
j++;k++;
next[j]=k;
}
else
k=next[k];
}
}
int kmpindex(sqstring s,sqstring t)//KMP模式匹配
{
int next[max],i=0,j=0;
getnext(t,next);
while(i<s.length &&j<t.length )
{
if(j==-1||s.data[i]==t.data[j])
{
i++;//i,j各增加
j++;
}
else
j=next[j];//i不变,j后退
}
if(j>=t.length )
return(i-t.length );//返回匹配模式串
else
return(-1);//返回不匹配标志
}
int main()
{
sqstring s,t;
int i,j,n,l,k;
char m,cstr[max],str[max];
printf("输入串cstr:");
i=0;
while((cstr[i]=getchar())!='\n')
i++;
cstr[i]='\0';
printf("输入串str;");
i=0;
while((str[i]=getchar())!='\n')
i++;
str[i]='\0';
printf("把串cstr赋值给串s:");
stra(s,cstr);
dis(s);
printf("把串str赋值给串t:");
stra(t,str);
dis(t);
printf("**** 1 BF匹配模式 ***********************************\n");
if(index(s,t)==-1)
printf("该顺序串不匹配!\n");
else
printf("该顺序串匹配,第一匹配位置是:%d\n",index(s,t));
printf("*****2 KMP匹配模式**********************************\n");
if(kmpindex(s,t)==-1)
printf("该顺序串不匹配!\n");
else
printf("该顺序串匹配,第一匹配位置是:%d\n",kmpindex(s,t));
return 0;
}
运行结果
复杂度分析
算法 | 时间复杂度 | 空间复杂度 |
---|---|---|
BF | n*m | 1 |
KMP | n+m | m |
BF算法比较直接,是一种蛮力算法。比如在一种极端情况下,主串为0000……01,然后模式串是00001,在这最坏情况下要进行m*(n-m+1)次比较,时间复杂度为O(nm)
KMP算法完成的任务是:给定两个字符串S和T,长度分别为n和m,判断f是否在S中出现,如果出现则返回出现的位置。常规方法是遍历a的每一个位置,然后从该位置开始和b进行匹配,但是这种方法的复杂度是O(nm)。则KMP算法通过一个O(m)的预处理,使匹配的复杂度降为O(n+m)。