字符串子串查找
BF:爆破法
KMP:3个人总结的,所以是3个人的名字结合
BF爆破法,就是由两个指针一个一个进行比较,比较字符如果不是一样的,则主串指针退回到比较开始的下一个字符重新开始,子串指针回到字串第一位字符。
如图所示:
KMP算法,则是在BF的基础上进行的优化,即比较字符的时候,上面的指针不动,下面指针归0,然后再进行比较。
如图所示:
又考虑到可能有特殊情况,aaaab和aaab这种类似刁民的东西。
特殊情况:
所以引入了一个K值进行针对。
K的意义是,父串和子串前面有K个字符相等
假设上面是i,下面是j,下面比较的下标就是j+=(k-1)
所以就会如图所示:
所以要专门准备一个函数,求这些K,所以我们可以制造一个next数组
没有找到则返回-1.
如图,可以看到BF算法和KMP算法,然后中间的是KMP在进行的时候k的值:-1 0 1 2.
代码如下:
#include<stdio.h>
#include<string.h>
struct Str
{
public:
char* pStr;
int len;
public:
Str()
{
pStr = NULL;
len = 0;
}
Str(const char* p)
{
len = strlen(p);
pStr = new char[len + 1];
memcpy(pStr, p, sizeof(char)*len);
pStr[len] = 0;//结束符号
}
Str(const Str& s)//拷贝函数
{
len = s.len;
if (0==len)
{
pStr = NULL;
}
else
{
pStr = new char[len + 1];
memcpy(pStr, s.pStr, sizeof(char) * (len+1));
}
}
};
//找字串 找到返回下标,没找到返回-1
//BF(brute-force暴力破解)
int BF(char* pStr1, char* pStr2);
//创建偏移表的函数
void getNext(Str s, int* next);
//KMP算法
int KMP(Str s1,Str s2);
int main()
{
Str s1("abcdaadaaaccdcd");
Str s2("aaac");
printf("BF: %d \n", BF(s1.pStr, s2.pStr));
printf("KMP: %d \n", KMP(s1, s2));
while (1)
{
}
return 0;
}
int BF(char* pStr1, char* pStr2)
{
int i = 0;//主串的
int j = 0;//字串的
int Idx = 0;//坐标
while (1)
{
if ('\0'==pStr1[i] || '\0' == pStr2[j])
{
break;
}
if (pStr1[i] == pStr2[j])
{
i++;
j++;
}
else
{
Idx++;
i = Idx;
j = 0;
}
}
if ('\0' == pStr2[j])
{
return Idx;
}
return -1;
}
void getNext(Str s, int* next)
{
char* pstr = s.pStr;
int len = s.len;
int j = 0; int k = -1;
next[0] = k;//第一个元素k=-1,表示j不动,i动
while (j<len)
{
if (k == -1 || pstr[j] == pstr[k])
{
//next[++j] = ++k;//next[j+1]=k+1
if (pstr[++j]==pstr[++k])
{
next[j] = k;
}
else
{
next[j] = k;
}
}
else
{
k = next[k];
}
}
}
int KMP(Str s1, Str s2)
{
char* pStr1 = s1.pStr;
char* pStr2 = s2.pStr;
int* next = new int[s2.len];
getNext(s2, next);
for (int i = 0; i < s2.len; i++)
{
printf("%d", next[i]);
}
printf("\n");
int i = 0;
int j = 0;
while (i<s1.len && j<s2.len)
{
if (-1==j ||pStr1[i]==pStr2[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if (j==s2.len)
{
return (i - j);
}
return -1;
}