串是由零个或多个字符组成的有限序列,又名字符串。
给定两个串: s=a1a2⋯an s = a 1 a 2 ⋯ a n , t=b1b2⋯bm t = b 1 b 2 ⋯ b m ,当满足以下条件之一时,s < t
1. n < m,且 ai=bi a i = b i (i = 1, 2, ……, n)
例如当s=“hap”,t=”happy”,就有s < t。因为t比s多出了两个字母
2. 存在某个k<=min(m,n),使得 ai=bi a i = b i (i = 1, 2, ……, k-1), ak<bk a k < b k
例如当s=”happen”,t=”happy”,因为两串的前4个字母均相同,而两串第5个字母(k值),字母e的ASCII码是101,而字母y的ASCII码是121,显然e < y,所以s < t
ADT 串(string)
Data
串中元素仅由一个字符组成,相邻元素具有前驱和后继关系。
Operation
StrAssign(T, *chars):生成一个其值等于字符串常量chars的串T
StrCopy(T, S):串S存在,由串S复制得串T
ClearString(S):串S存在,将串清空
StringEmpty(S):若串S为空,返回true,否则返回false
StrLength(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
StrDelete(S, pos, len):串S存在,1 <= pos <= StrLength(S) - len + 1。
从串S中删除第pos个字符起长度为len的子串
endADT
串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的。
对于串的链式存储结构,与线型表是相似的,一个结点可以存放一个或多个字符,最后一个结点若未被占满,可以用其他字符补全。
字符串的定位操作通常称做串的模式匹配
朴素模式匹配,即通过挨个遍历的方法进行比对,效率相对底下。
/* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */
/* T非空,1 <= pos <= StrLength(S) */
int Index(String s, String T, int pos) {
int i = pos;
int j = 1;
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;
}
}
我们可以根据经验得到如果前后缀一个字符相等,k值是2,两个字符k值是3,n个相等k值就是n + 1。
/* 通过计算返回子串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];
}
}
/* 返回子串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;
}
/* 求模式串T的next函数修正值并存入数组nextval */
void get_nextval(String T, int *nextval) {
int i, j;
i = 1;
j = 0;
nextval[1] = 0;
while(i < T[0]) {
if(j == 0 || T[i] == T[j]) {
++i;
++j;
if(T[i] != T[j])
nextval[i] = j;
else
nextval[i] = nextval[j];
} else
j = nextval[j];
}
}
实际匹配算法,只需要将”get_next(T, next;”改为”get_nextval(T, next)”