串
1.串的定义
串是由零个或多个字符组成的有限序列,又名叫字符串。
一般记为s=“a1a2······an”(n>=0) s是串的名称,双引号里面是串的值,注意引号不是串的内容,n称为串的长度。
空串:零个字符的串,长度为0
空格串:只包含空格的串,可以不止一个空格,注意它与空串的区别
子串与主串:串中任意个数的连续字符组成的子序列称为该串的子串,相应的,包含字串的串称为主串
子串在主串的位置就是子串的第一个字符在主串中的序号
2.串的存储结构
串的顺序存储结构
#define MAXLEN 255
typedef struct{
char ch[MAXLEN+1];//存储串的一维数组
int length;//串的当前长度长度
}SString;
串的链式存储结构----块链结构
#define CHUNKSIZE 80//块的大小可由用户定义
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk*next;
}Chunk;
typedef struct{
Chunk*head,*tail;//串的头指针和尾指针
int curlen;//串的当前长度
}LString;//字符串的块链结构
3.朴素的模式匹配算法-BF算法
Index(S,T,pos)
将主串的第pos个字符和模式串的第一个字符比较,
若相等,继续逐个比较后续字符
若不等,从主串的下一个字符起,重新与模式串的第一个字符比较
直到主串的一个连续子串字符序列与模式串相等,返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功。否则匹配失败,返回值0
int Index_BF(SString S,SString T){
int i=1,j=1;
while(i<=S.length&&j<=T.length){
if(s.ch[i]==t.ch[j]){
++i;
++j;
}//主串和子串依次匹配下一个字符
else{
i=i-j+2;
j=1;
}//主串和子串指针回溯重新开始下一次匹配
}
if(j>=T.length)
return i-T.length;//返回匹配的第一个字符下标
else
return 0;//模式匹配不成功
}
4.广义表
广义表通常记作:LS=(a1,a2,…an)
其中:LS为表名,n为表的长度,每一个ai为表的元素
习惯上,一般用大写字母表示广义表,小写字母表示原子
表头:若LS非空(n>=1),则其第一个元素a1就是表头
记作head(LS)=a1 注意:表头可以是原子,也可以是子表。
表尾:除表头之外的其它元素组成的表
记作 tail(LS)=(a2,…,an) 注意:表尾不是最后一个元素,而是一个子表。
5.KMP模式匹配算法
//通过计算返回子串T的next数组
void get_next(String T,int *next)
{
int i;
int 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;//表示下标为i的字符前的字符串最长相等前后缀长度
}
else
j=next[j];//若字符不相同,则j值回溯
}
}
int Index_KMP(String S,String T,int pos)
{
//T非空,1<=pos<=StrLength(S)
int i=pos;//i用于主串S当前位置下标值,若pos不为1,则从pos位置开始匹配
int j=1;//j用于子串T中当前位置下标值
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];//j退回合适的位置,i值不变
}
}
if(j>T[0])
return i-T[0];
else
return 0;
}
next数组值推导
如何推导出一个串的next数组值呢?
T=“abcdex"
j | 123456 |
---|---|
模式串T | abcdex |
next[j] | 011111 |
(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",显然”a"与“b"不相等,属于其他情况next[3]=1
(4)以后同理,所以最终此T串的next[j]为011111
这个大家不好理解,就来看看下面我的理解,希望帮助到大家
问题:已知串S= ‘ababaaaba’ , 求其 next 数值序列
前面有k-1个字符一样
(1).next数组第一二位一定分别为0,1
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a | a | b | a |
next[j] | 0 | 1 |
(2)看第三位,按照next数组求解方法。第三位a的前一位是第二位的b,b的next值是1对应内容是a,b与a不同,则继续向前寻找next值对应的内容与第二位的b进行比较。但是找到第一位都没有找到与第二位的b相等的内容,所以第三位a的next值为1,则:
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a | a | b | a |
next[j] | 0 | 1 | 1 |
(3)看第四位的b,b的前一位a的next值1对应内容为a,相同,所以该位b的next值就是前一位a的next(第三位的a)值加上1,即为2 (aba)
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a | a | b | a |
next[j] | 0 | 1 | 1 | 2 |
(4)看第五位a,a的前一位b的next值2对应内容为b,相等,所以第五位a的next值就是其前一位b的next值加上1,即为3 (abab)
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a | a | b | a |
next[j] | 0 | 1 | 1 | 2 | 3 |
(5)看第六位a,a的前一位a的next值3对应内容为a,相等,所以该位a的next值就是前一位a的next值加上1,即为4 (ababa)
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a | a | b | a |
next[j] | 0 | 1 | 1 | 2 | 3 | 4 |
(6)看第七位a,a的前一位a的next值4对应内容为b,不相等,向前继续寻找next值对应的内容来与前一位进行比较,b的next值2对应的内容为b,依旧不相等,继续向前寻找,第二位b的next值1对应内容为a,相等。因为是在第二位b处实现的相等,所以第七位a的next值为第二位b的next值上加1,即为2 (ababaa)
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a | a | b | a |
next[j] | 0 | 1 | 1 | 2 | 3 | 4 | 2 |
(7)看第八位b,b的前一位a的next值2对应内容为b,不相等,向前继续寻找next值对应的内容来与前一位进行比较,b的next值1对应的内容为a,相等。因为是在第二位b处实现的相等,所以第八位a的next值为第二位b的next值上加1,即为2 (ababaaa)
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a | a | b | a |
next[j] | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 |
(8)看第九位,前一位b的next值2对应内容为b,相等,所以此处next值为3 (ababaaab)
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a | a | b | a |
next[j] | 0 | 1 | 1 | 2 | 3 | 4 | 2 | 2 | 3 |