1、串的顺序存储结构
- 串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。一般是用定长数组来定义。
2、串的链式存储结构
- 串的链式存储结构,与线性表是相似的,但由于串结构的特殊性,结构中的每个元素数据是一个字符,如果也简单的应用链表存储串值,一个结点对应一个字符,就会存在很大的浪费。因此,一个结点可以存放一个字符,也可以考虑存放多个字符,最后一个结点若是没有被占满时,可以用“#”或其他非串值字符补。
3、朴素的模式匹配算法
- 子串的定位操作通常称作串的模式匹配,是串中最重要的操作之一。假设主串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]) /*若i小于S长度且j小于T的长度时循环*/
{
if(S[i] == T[j]) /*两字母相等则继续*/
{
++i;
++j;
}
else /*指针后退重新开始匹配*/
{
i = i - j + 2; /*i退回到上次匹配首位的下一位*/
j = 1; /*j退回到子串T的首位*/
}
}
if(j > T[0])
return i - T[0];
else
return 0;
}
4、KMP模式匹配算法
- KMP模式匹配算法的实现
/*通过计算返回子串T的next数组。*/
void get_next(String T, int *next)
{
int i, j;
i = 1;
j = 0;
next[1] = 0;
while(i < T[0]) /*此处T[0]表示串T的长度*/
{
if(j == 0 || T[i] == T[j]) /*T[i]表示后缀的单个字符,T[j]表示前缀的单个字符*/
{
++i;
++j;
next[i] = j;
}
else
j = next[j]; /*若字符不相同,则j值回溯*/
}
}
这段代码的目的就是为了计算出当前要匹配的串T的next数组。如果前后缀n个字符相等k值就是n + 1。
/*返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0*/
/*T非空,1<= pos =< StrLength(S).*/
int Index_KMP(String S, String T, int pos)
{
int i = pos;
int j = 1;
int next[255];
get_next(T, next);
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;
}
- KMP模式匹配算法改进
/*求模式串T的next函数修正值并存入数组nextval。*/
void get_nextval(String T, int *nextval)
{
int i, j;
i = 1;
j = 0;
nextval[1] = 0;
while(i < T[0]) /*此处T[0]表示串T的长度*/
{
if(j == 0 || T[i] == T[j]) /*T[i]表示后缀的单个字符,T[j]表示前缀的单个字符*/
{
++i;
++j;
if(T[i] != T[j]) /*若当前字符与前缀字符不同,则当前的j为nextval在i位置的值*/
nextval[i] = j;
else
nextval[i] = nextval[j]; /*如果与前缀字符相同,则将前缀字符的nextval值*/
/*赋值给nextval在i位置的值*/
}
else
j = next[j]; /*若字符不相同,则j值回溯*/
}
}
实际匹配算法,只需将“get_next(T, next)”改为“get_nextval(T, next)”即可。