一、定义:由零个或多个字符组成的有限序列
逻辑结构:内容受限的线性表,元素为字符型
存储结构:
顺序存储
链式存储:最后一个节点未被占满时,可用“#”或其他非串值字符补全
运算:比较、合并、插入、删除、替换、求子串、匹配
//T为非空串。若主串S中第pos个字符之后存在与T相等的子串,则返回第一个这样的子串在S中的位置,否则返//回0
int Index(String S,String T,int pos)
{
int n,m,i;
String sub;
if(pos > 0)
{
n = StrLength(S);//主串S的长度
m = StrLength(T);//子串T的长度
i = pos;
while( i <= n-m+1)
{
SubString(sub,S,i,m);//取主串第i个位置,长度与T相等子串给sub
if(StrCompare(Sub,T) != 0)//两串不等
++i;
else
return i;//若等,返回i值
}
}
return 0;//若无子串与T相等,返回0
}
二、朴素的模式匹配算法:子串的定位操作通常称做串的模式匹配。
//假设主串S和要匹配的子串T的长度存在S[0]与T[0]中,返回子串T在主串S中第pos个字符之后的位置
//若不存在,则函数返回为0
//T非空 1<=pos<=StrLength(S)
int Index(String S,String T,int pos)
{
int i = pos;//i用于主串S中当前位置下标,若pos不为1,则从pos位置开始匹配
int j = 1;//j用于子串T中当前位置下标值
while(i <= S[0] && j <= T[0])
{
if(S[i] == T[j])//若相等
{
++i;
++j;
}
else//指针后退重新开始匹配
{
i = i-j+2;
j =1;
}
}
if(j > T[0])
return i - T[0];
else
return 0;
}
最好时间复杂度:O(n+m)
最坏时间复杂度:O((n-m+1)*m)
但是效率低下。
三、KMP模式匹配算法:为了让没必要的回溯不发生
主串S:i
子串T:j
j值的变化与主串其实没有什么关系,关键就取决于T串的结构中是否有重复值的问题
eg:
S = "abcabcabc"
T = "abcabx"
j
j值的多少取决于当前字符之前的串的前后缀的相似度,把T串各个位置的j值的变化定义为一个数组next,next的长度就是T串的长度
next[j] = { 0,j = 1
Max{k |1 < k <j,且‘p1...k-1' = 'Pj-k+1...Pj-1'} 不为空时
1,else
int Index_KMP(SString S,SString T,int pos,int next[])
{
//利用模式串T的next函数求T在主串中S中第pos个字符之后的位置,其中,T非空,1 <= pos <=S[0]
//S[0]为模式串S的长度
int i = pos,i = 1;
while(i <= S[0]&&j <= T[0])
{
if(j == 0||S[i] == T[j])//继续比较后面的字符串
{
i++;
j++;
}
else
j = next[j];//向右移动
}
if(j > T[0])//匹配成功
return i - T[0];
else
return 0;
}
时间复杂度:O(n+m)
四、改进的KMP算法
void get_next(SString S,int next[])//求T串的next函数值
{
int j = 1,k = 0;
next[1] = 0;
while(j < T[0])//T[0]为串T的长度
if(k == 0 || T[j] == T[k])
next[++j] = ++k;
else
k = next[k];
}
//时间复杂度:O(n+m)