基本操作
首先,串是由零个或多个字符组成的有穷序列,其次它也是一个特殊的线性表。
串相等:长度相同且各个对应位置上的字符相同
真子串=子串+空串
子串=(n+1)n/2
这里我们要讲下它的链式存储的赋值操作:
我们采用的是尾插法(这样我们得到的就是和序列顺序相同的链表)
p=(LiSting *)malloc(sizeof(LiString));//创建新的结点
p->data=cstr[];//赋值
r->next=p;
r=p;
这里我们重点要理解后2行代码
BF算法
很简单,BF算法就是我们常理解的那种。当不匹配时,就将模式串从模式串的下一个字符重新比较;
这里我们关键要注意的是:
i是如何回溯的,这里就不进行推导了,直接给出结论:
i=i-j+1
KMP算法
记模式串的长度为m,匹配串的长度为n
可以算出BF算法的时间复杂度是T(n)=O(m×(m-n))
那么这个时间复杂度算是很大的了,这里我们引入KMP算法
KMP算法:
首先我们引入数组next[ ] ,匹配串设置为:a b a a b c a c
然后建一个表
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
t.data [ j ] | a | b | a | a | b | c | a | c |
next [ j ] | -1 | 0 | 0 | 1 | 1 | 2 | 0 | 1 |
那么next[ ]要如何求呢?
那么用通俗的语言来说一遍:
我们姑且直接定义当j=0时, next [ j ]=-1;j=1时, next [ j ]=0
然后我们依次来看
- j=2;我们可以看到a=1与a=0的值不一样,即next [ j ]=0
- j=3;a=2的值与a=0的值一样,但ab与ba不一样,即next [ j ]=1
- j=4;a=3的值与a=0的值一样,但aa与ab不一样,即next [ j ]=1
- j=5;a=4的值与a=0的值一样,但第一个ab与后面的ab相同,那么我们可以知道next [ j ]的值起码为2;那看看下一个aba与aab不同,所以next [ j ]=3
- j=6;a=5的值与a=0的值不一样,所以next [ j ]=0
- j=7;a=6的值与a=0的值一样,但ab与ca不同,即next [ j ]=1
下面给出next [ j ]的算法
void GetNext(SqString t,int 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])
{
j++;k++;
next[j]=k;
}
else
k=next[k];
}
}
当出现不匹配情况时;
j=next[j]
给出KMP算法代码,建议自己代入运行一遍
int KMPIndex(SqString s,SqString t)
{
int next[MaxSize],i=0,j=0;
GetNext(t,next);
whlie(i<s.length&&j<t,length)
{
if(j==-1||s.data[i]==t.data[j])
{
i++;
j++;
}
else
j=next[j];
}
if(j>=t.length)
return (i-t.length)
else
return (-1)
}