串:
由零个或多个字符构成的有限序列,又叫字符串
一般记为:s=”a1a2a3……an”
子串和主串:
串中任意个数的连续字符组成的子序列称为该串的子串 子串在主串中的位置就是子串的第一个字符在主串中的序号
串的比较:
给定两个串:s=”a1a2a3……an”,t=”b1b2b3……bm”,当满足以下条件之一时,s
串的存储结构:
顺序存储结构:
用一组地址连续的存储单元来存储串中的字符序列。
按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区,一般是用定长数组来定义
数组中也会存储预定义的最大串长度,一般可以将串的长度放在数组0处,或者数组最后,或者规定在串的最后加一个终结符,比如“\0”(表示串的结束)
缺点:
对于一些对字符串的操作(改变字符串长度),比如两串的连接Concat、新串的插入等操作,都有可能使得串序列的长度超过了数组长度MaxSize,会与定长冲突
链式存储结构:
一个结点可以存放一个字符,也可以存放多个字符,最后一个结点若是没有被占满,可以用”#”或其他非串值字符补全
链式存储结构在连接串上方便,但是不如顺序存储灵活,性能也不如顺序存储结构
串的操作:
不同的编程语言有不同的串操作,不过大体上是一样的,接触语言时可以看看API
模式匹配算法:
朴素的模式匹配算法:
1) 从主S的第一个字符起和子串T的第一个字符进行比较,若相等,则继续逐个比较主串和子串的后续字符,否则从串主串S的下一个字符起再重新和子串T进行比较。
2) 依此类推,直至子串T中的每个字符依次和主串S的一个连续的字符序列相等,则称模式匹配成功,此时子串T的第一个字符在主串S中的位置就是T在S中的位置,否则模式匹配不成功。
/**
* S : 主串
* T : 子串
* pos : 从pso位置后面开始匹配
* 注意:数组的0位置存储数组的长度
*/
int index(String S, String T, int pos)
{
int i = pos; // i是主串字符上的指针
int j = 1; // j是子串当前位置
while(i <= S[0] && j <= T[0])
{
// 字符匹配成功,匹配下一个字符
if(S[i] == T[j])
{
++ i;
++ j;
}
// 字符匹配失败
else
{
i = (i-j+1) + 1; // 主串指针回到开始匹配位置的下一个位置
j = 1; // 子串指针回到开始
}
}
// 子串匹配成功
if(j > T[0])
return i - T[0];
// 子串匹配失败
else
return 0;
}
KMP模式匹配算法:
i:主串和子串比较时,主串当前位置的下标
主串和子串比较时,不用回溯i指针(不可以变小)
举例:
主串S=”abcababca”,子串T=”abcabx”
第1步:对于开始的比较,前5个字符相等,
第4步:T的首位”a”与T的第四位的”a”相等,后面的”b”也相等。
而在第1步的时候,第四位的”a”和第五位的”b”已经和主串中相应的位置已经比较为相等,所以T的首字符”a”和下一位的”b”就不需要再比较了。
在这里,我们只要确定T串中各个位置的j值的变化定义为一个数组next,那么next的长度就是T串的长度。
注:p1,p2,…,pj-1是T串每个位置上的元素
注意:
第二种情况确定j,可以利用前缀字符和后缀字符相等的字符数n个(j=n+1)
1. 当j=1时,next[1]=0
2. 当j=2时,j由1到j-1的串是”a”,next[2]=1
3. 当j=3时,j由1到j-1的串是”ab”,next[3]=1
4. 当j=4时,j由1到j-1的串是”aba”,前缀字符”a”与后缀字符”a”相等,所以next[4]=1
5. 当j=5时,j由1到j-1的串是”abab”,前缀字符”ab”与后缀字符”ab”相等,所以next[5]=3
6. 当j=6时,j由1到j-1的串是”ababa”,前缀字符”aba”与后缀字符”aba”相等,所以next[6]=4
7. 当j=7时,j由1到j-1的串是”ababaa”,前缀字符”a”与后缀字符”a”相等,所以next[7]=2
8. 当j=8时,j由1到j-1的串是”ababaaa”,前缀字符”a”与后缀字符”a”相等,所以next[8]=2
9. 当j=9时,j由1到j-1的串是”ababaaab”,前缀字符”ab”与后缀字符”ab”相等,所以next[9]=3
算法实现:
通过计算返回子串T的next数组:
void getNext(String T, int *next)
{
int i, j;
i = 1;
j = 0;
next[1] = 0;
while(i < T[0]) // 0处存放数组长度
{
if(j == 0 || T[i] == T[j])
{
++ i;
++ j;
next[i] = j;
}
else{
j = next[j];
}
}
}
返回子串T在主串S中第pos个字符后的位置
int index(String S, String T, int pos)
{
int i = pos; // i指示主串S的位置
int j =1; // j指示子串T的位置
int next[255]; // 定义一个next数组
getNext(T, next); // 获取T的next数组
while(i <= S[0] && j <= T[0]) // S[0]和T[0]存放数组长度
{
if(j == 0 || S[i] == T[j]) // 两字母相等就继续
{
++ i;
++ j;
}
else // 指针后退重新比较
{
j = next[j]; // j退回合适的位置,i值不变
}
}
if(j > T[0])
return i - T[0];
else
return 0;
}