您的位置:首页 > 其它

BF算法与KMP算法

2018-01-28 18:00 211 查看

BF算法

两个字符串 str sub



算法基本思想:

初始 i=0,j=0

1、当str[i]==sub[j]时i++,j++;

2、当str[i]!=sub[j]时,i=i-j+1,j=0;

3、当j>=strlen(str)或者i>=strlen(sub)结束

BF 算法的时间复杂度是:O(mn)

m 代表主串的长度, n 代表子串的长度。

代码实现:

int BF(const char *str, const char *sub, int pos)
{
int lenstr = strlen(str);
int lensub = strlen(sub);

if (pos < 0 || pos>lenstr)
{
return -1;
}

int i = pos;
int j = 0;

while (i < lenstr&&j < lensub)
{
if (str[i] == sub[j])
{
i++;
j++;
}
else
{
i = i - j + 1;
j = 0;
}
}

if (j >= lensub)
{
return i - j;
}
return -1;
}


KMP算法

KMP 算法更为高效

时间复杂度为 O(m+n)

m 代表主串的长度, n 代表子串的长度。

KMP 和 BF 唯一不一样的地方在:主串的 i 并不会回退, 并且 j 也不会移动到 0 号位置。

那j该如何退呢?

当 i 和 j 走到如下图位置



j 不需要回退到0,而是回退到上一个‘c‘的位置即可,假设每次回退为“K”位置。

我们要在确定sub中匹配到那一位不同时回退到对应的k位置,把所有的k都保存在next[strlen(sub)]数组中。

那如何确定每次回退到哪呢?

如上图i=j=5时,str[i]!=sub[j],(用P0表示str[0]的字符,用S0表示sub[0]的字符)所以可以保证

P0P1P2P3P4=S0S1S2S3S4

这是观察可得应把j回退到S2即可,由于S0S1==P3P4==S3S4

同理假设str[i]!=sub[j]



P0P1P2,,,,,Pi ==S0S1S2,,,,,Sj

回退到k

存在S0,,,Sk-1 == Pi-k,,,Pi-1==Sj-k,,,,,Sj-1

第j位不同时,回退到k位置

so, next[j] = k ————条件1

由于当0号下标不同时,我们就会让j回退到当前位置,

但是默认next[0]=-1———条件2

由于当1号下标不同时,我们就会让j回退到0号位置,

so,next[1]=0———条件3

我们要根据已知的三个条件求 next[2] next[3],,,,,,,直到求出所有的next数组

由于Sj 与 Sk只存在两种关系 1、Sj = Sk 2、Sj != Sk

根据这两种关系我们做出两种假设

假设1、Sj = Sk

这时

S0,,,Sk-1 == Pi-k,,,Pi-1==Sj-k,,,,,Sj-1 【1】就可以拓展为

S0,,,Sk-1Sk ==Sj-k,,,,,Sj-1Sj 【2】

由于在【1】==>next[j] = k

so, 【2】==>next[j+1]=k+1

假设2、Sj != Sk ,如下图S2!=S5



这时由多次观察总结得

S5本来按Sj==Sk,应该回退到2位置但是很明显,S2!=S5,这时让k继续回退到2的k值====>k=next[k]

如此,就能求得所有next数组的值

每次遇到不同,让j回退到next[j]

代码实现

void GetNext(char *sub,int *next)
{
int lensub = strlen(sub);
next[0] = -1;
next[1] = 0;
int i = 2;//第二项
int k = 0;
while (i < lensub)
{
if ((k == -1) || sub[k] == sub[i -1])
{
next[i] = k + 1;
i++;
k++;
}
else
{
k = next[k];
}
}
}

int KMP(char *str, char *sub, int pos)
{
int lenstr = strlen(str);
int lensub = strlen(sub);

if (pos < 0 || pos>lenstr)
{
return -1;
}

int i = pos;
int j = 0;

int *next = (int *)malloc(sizeof(int)*strlen(sub));
assert(next != NULL);
GetNext(sub, next);
while (i < lenstr &&j < lensub)
{
if ((j == -1) || str[i] == sub[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if (j >= lensub)
{
return i - j;
}
return -1;
}


4000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  KMP BF