04 串
-
定义
串(String)是由零个或多个字符组成的有限序列,又名叫字符串。
ADT 串(string) Data 串中元素仅由一个字符组成,相邻元素具有前驱和后继关系 Operation StrAssign(T,*chars):生成一个其值等于字符串常量chars的串T。 StrCopy(T,S):串S存在,由串S复制得串T。 ClearString(S):串S存在,将串清空。 StringEmpty(S):若串为空,则返回true,否则返回false。 StrLength(S):返回S的元素个数,即串S的长度。 StrCompare(S,T):若S>T,返回>0,S=T,返回=0,S<T,返回<0. Concat(T,S1,S2):用T返回由S1和S2联接而成的新串。 SubString(Sub,S,pos,len):串S存在,1<=pos<=Strlength(S), 且0<=len<=Strlength(S)-pos+1. 用Sub返回串S的第pos个字符起长 度为len的子串。 Index(S,T,pos):串S和T存在,T是非空串,1<=pos<=Strlength(S). 若主串S中存在和串T值相同的字串,则返回它在主 串S中第pos个字符之后第一次出现的位置,否则返回0 Replace(S,T,V):串S,T和V存在,T是非空串。用V替换主串S中出现 的所有与T相等的不重叠的子串。 StrInsert(S,pos,T):串S和T存在,1<=pos<=Strlength(S)+1.在串S的 第pos个字符之前插入串T。 SteDelete(S,pos,len):串S存在,1<=pos<=StrLength(s)-len+1.从串 S中删除第pos个字符起长度为len的子串。
-
顺序存储结构
-
链式存储结构
-
朴素的模式匹配算法:最坏情况的时间复杂度为O((n-m+1)*m)
子串的定位操作通常称做串的模式匹配
/* 朴素的模式匹配法 */
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;
}
-
KMP模式匹配算法
- 原理
- 实现
对于get_next函数来说,若T的长度为m,因只涉及到简单的单循环,其时间复杂度为O(m),而由于i值不回溯,使得index_KMP算法效率得以提高,while循环的时间复杂度为O(n)。因此,整个算法的时间复杂度为O(m+n)。相较于朴素模式匹配算法的O((n-m+1)*m)来说,是要好一些。但这里也需要强调,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在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */ /* T非空,1≤pos≤StrLength(S)。 */ int Index_KMP(String S, String T, int pos) { int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */ int j = 1; /* j用于子串T中当前位置下标值 */ int next[255]; /* 定义一next数组 */ get_next(T, next); /* 对串T作分析,得到next数组 */ while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */ { if (j==0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */ { ++i; ++j; } else /* 指针后退重新开始匹配 */ j = next[j];/* j退回合适的位置,i值不变 */ } if (j > T[0]) return i-T[0]; else return 0; }
-
改进:将get_next(T,next)改为get_nextval(T,next)
/* 求模式串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]) /* 若当前字符与前缀字符不同 */ nextval[i] = j; /* 则当前的j为nextval在i位置的值 */ else nextval[i] = nextval[j]; /* 如果与前缀字符相同,则将前缀字符的 */ /* nextval值赋值给nextval在i位置的值 */ } else j= nextval[j]; /* 若字符不相同,则j值回溯 */ } }