有两个字符串,一个为str,一个为pat。
我们的目的是查找pat在str中出现的位置。
最简单的办法无非就是两层循环。
for(int i=0; i<strlen(str); i++)
{
for(int j=0; j<strlen(pat); j++)
{
if(str[i+j] != pat[j]
break;
}
if(j < strlen(pat))
break;
else
index = i; //index保存str中pat子串出现的首位置
}
if(i < strlen(str))
printf("Match success!The index is:%d",index);
else
printf("Match failed");
以上这个算法虽然简单,但是效率不高。
我们需要一个更高效的算法
我们先来看一个例子,
char *str = “abcaccabcabcac”;
char *pat= “abcabcac”;
我们先按照最简单的算法走。
设定匹配到str中的位置为i,匹配到pat中的位置为j;
当我们匹配到 i=4,j=4的时候。
已经不能匹配了,这时候我们就需要将i+1,而j又要从0开始。
当然,这样是完全可以得到正确的结果的。
但是,当我们仔细观察pat的时候发现。当我们接下来用i=5和j进行匹配的时候,我们可以直接和j=1进行匹配,而不用进行j=0时候的匹配。
因为我们的pat子串中的pat[0]~pat[3]和pat[3]~pat[6]是相同的。
这样我们就不必去比较j=0的情况。
这就意味着,如果在pat中是一个满足一定条件的子串,我们就不用每次都将j从第0个位置开始匹配,而是可以根据一些规律,有选择的选择j的位置。
定义:模式串P=p(0)p(1)……p(n-1)的失配函数定义如下:
若存在p(0)p(1)……p(i) = p(j-i)p(j-i+1)……p(j), i小于j;
f(j) = max{i,0};
否则,f(j) = -1;
例如模式串P = ‘a b c a b c a c a b’, 失配函数是
j 0 1 2 3 4 5 6 7 8 9
P a b c a b c a c a b
f(j) -1 -1 -1 0 1 2 3 -1 0 1
有了失配函数,我们很容易得到一个规则
如果部分匹配结果是s(i-j)……s(i-1) = p(0)p(1)……p(j-1)且si 不等于 pj。
则接下来如果 j 不等于0,应该用 si 与p( f(i-1)+1 )相比,如果j = 0,应该用p(0)与s(i+1)相比。
下面是程序
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define M 101
//失配函数
void fun(char *arr, int res[])
{
res[0] = -1;
for(int i=1; i<strlen(arr); i++)
{
int j=0;
if(arr[i] != arr[j])
{
res[i] = -1;
}
else
{
while(arr[i] == arr[j] && i<strlen(arr))
{
res[i] = j;
i++;
j++;
}
i--;
}
}
}
int main()
{
char str[M],pat[M];
int f[M];
int i=0,j=0;
gets(str);
gets(pat);
fun(pat,f);
while(i < strlen(str) && j < strlen(pat))
{
if(str[i] == pat[j])
{
i++;
j++;
}
else if(j == 0)
i++;
else
j = f[j-1] + 1;
}
if(j == strlen(pat))
printf("Match success!\n The %s is in %s at %d",pat,str,i-strlen(pat));
else
puts("Match failed!");
}