数据结构:串的知识总结,BF,KMP算法
常见基础概念
- 串长:串中字符个数,有时还常用a[0]/length来存储串长
- 注意空串和空格串的区别
空串是长度为0的串,而空格串是由多个或一个空格字符组成的字符串
- 子串与主串:串S中任意个连续字符序列叫S的子串,S称为主串
- 子串位置: 子串的第一个字符在主串中的序号(序号从1开始)
- 字符位置:字符在串中的序号
- 串相等:长度和对应字符均相等
类c中的常见操作
- StrAssign(&T,chars)//给T串赋值
- StrCompare(S,T)比较S,T两串,若S>T,则返回非0
- StrLength(S)求串S的长度
- Concat(&T,s1,s2)串连接,返回T
- SubString(&Sub,S,pos,len)求S中pos起长度为len的子串
- int Index(S,T,pos)模式匹配
- Replace(&S,T,V)用V替换T
C语言中提供的操作函数
int strcmp(char *s1,char *s2)//串比较
int strlen(char *s1)//求串长
char strcat(char *to,char *from)//串连接
char strchr(char *s,char *c)//模式识别
//详见C语言程序设计
定长存储
#define Maxstrlen 255
typedef unsigned char SString[Maxstlen+1]SString;
SString s;//s是一个能够容纳255字符的顺序串
- 一般用SString[0]存储串长信息
- C语言中串尾会加上结束符‘\0’,但不计入串长
- 字符串超过Maxstlen就会自动截断,因为静态数组不能溢出
顺序储存方式实现SubString(&Sub,S,pos,len)
//这里以int型为例,且默认Sub为空数组
int SubString(SString Sub,SString S,int pos,int len)
//这里SString相当于char SSring[],详见typedef的用法
{
if(pos<1||pos>S[0]||len<0||len>s[0]-pos+1)
return -1;//判断pos和len是否越界
for(int i=1;i<=len;i++)
{
Sub[i]=S[pos+i-1];
}
Sub[0]=len;
return 0;
}
堆分配的储存结构
- 简单来说就是建立动态数组,优于定长存储
typedef struct{
char *ch;//为空串时指定ch=NULL
int length;
}Hstring;
//堆分配是采用了mallco预设串长度,用realloc增加长度,用free释放空间
int StrAssign(Hstring *T,char *chars)
{
int i;
if(T->ch) free(T->ch);
for(i=0,c=chars;c;c++);//计算chars的长度i
if(!i){
T->ch=NULL;
T->length=0;
}//判断chars是否为空
else {
if(!(T->ch=(char *)malloc(i*sieof(char)))
return -1;
T->length=i;
for(;i;i--)
{
T->ch[i-1]=chars[i-1]
}//这里T->ch[0}没有用来装串长
}
return 0;
}//赋值函数
利用堆方式编写串插入函数
int StrInsert(Hstring *S,int pos,Hstring T)
{ //在串的第pos个位置前插入
if(pos<1||pos>S->length+1)
return -1;
if(!(S->ch=(char *)realloc(S->ch,(T.length+S->length)*sizeof(char)))
return -1;
for(int i=S->length-1;i>=pos-1;i--)
S->ch[i+T.length-1]=S->ch[i];//T的插入腾出空间
for(int i=0;i<=T.length-1;i++)
{ S->ch[i+pos-1]=T.ch[i];
S->length+=T.length;
}
return 0;
}
链式存储
块链的写法
#define Size 100
typedef struct Chunk{
char ch[Size];
struct Chunk *next;
}Chunk,*ListChunk;
BF算法的实现
将主串S的第pos个字符和模式T的第一个字符比较,若相等,继续逐个比较后续字符;若不相等,从主串的下一个字符(pos+1)起,重新与T第一个字符比较,直到匹配成功,返回S中与T匹配子序列第一个字符的序号。否则返回0
//BF算法的实现
int Index_BP(SString S,SString T,int pos)
{
//这里已经默认1<=pos<=S[0]
int i=pos,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;
}
KMP算法(优化,i不再回溯,j的回溯距离变短)
关键在于next[j]的求解
//采用了递推法求next[j]
void get_next(SString T,int next[])
{
int i=1,j=0;
next[1]=0;
while(i<T[0])
if(j==0||T[i]==T[j])
{
i++;j++;
next[i]=j;
}
else j=next[j];//从类似于KMP的求解,T为主串和模式串
}
算法实现
int Index_KMP(SString S,SString T,int pos)//省略