1.串:由零个或多个字符所组成的有限序列,称为字符串。
2.空串和空格串:空串是零个字符的串,长度为零。空格串是只包含空格的串,有长度,可以不止一个空格。
3.串的比较:比较第一个不同的字符来比较串的大小。排在前面的字符小于排在后面的字符。大写字符全部排在前面。
4.串的应用:
计算机中常用的是ASCII编码,由八位二进制位表示一个字符,总共可以表示256个字符。后来又有了Unicode编码,常用16为二进制数表示一个字符,总共就可以表示约65万多个字符,足够表示世界上所有语言的字符了。
5.串的存储结构:
顺序存储时分配一组连续的存储单元,实现定义固定的长度来存储串。若超过这个长度就截断。要得到串长度,可以在末尾加上一个null位表示结束,也可以在串首s[0]存储串的长度,两者都会占用一个空间,后者更为方便。
堆分配存储表示:在堆的自由存储区里动态分配malloc(),free()一块连续的存储空间给串。
typedef struct{
char *ch;
int length;
}HString;
在串s的第pos个字符之前插入串T。
Status StrInsert(HString &S, int pos, HString T)
{
if(pos<1 | pos>S.length+1) return ERROR;
if(T.length)
{
if(!(S.ch= (char *)realloc(S.ch,(S.length+T.length)*sizeof(char))))
exit(OVERFLOW);
for(i = S.length-1; i>=pos-1; --i)//为插入T 腾出空间
S.ch[i+T.length] = S.ch[i];
S.ch[pos-1..pos+T.length-2] = T.ch[0..T.lenth-1];
S.length += T.length;
}
return OK;
}
串的块链存储表示:每个节点只存放一个字符太过浪费,可以多个字符存在一个节点中,不足的空间存放#。
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk *next;
}Chunk;
typedef struct{
Chunk *head, *tail;
int curlen;
}String;
串的存储密度是串值所占的存储位/实际分配的存储位。显然,存储密度小时,运算处理方便,存储占用量大。总的来说,如果需要连接操作链式存储结构比较好,其他时候链式存储没有另外两种存储结构灵活,占用存储量大,且操作复杂。
6.朴素的模式匹配算法:子串的定位操作通常称作串的模式匹配。
返回子串T在主串S中第pos个字符之后的位置。若不存在返回0。
int Index(String S, String T, int pos)
{
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;} //i要退到上次匹配首位的下一位
}
if(j>T[0]) return i-T[0];
else return 0;
}
时间复杂度分析:最好就是第一次就成功了,O(1).其次就是首字母每次都不匹配,对T串的循环就不用了,这时的时间复杂度是O(n+m).最坏的情况是每一次的不匹配发生在串T的最后一个字符,时间复杂度为O((n-m+1)*m).
7.KMP模式匹配算法:根据T串的性质来决定每次循环中j退回到哪里。i从来不回退,避免重复的比较。时间复杂度是O(n+m)。
void get_next(String T, int *next)
{
int i=1,j=0;//i表示后缀,j表示前缀
next[1]=0;
while(i<T[0])
{
if( j==0 || T[i]==T[j])
{
++i;++j;
next[i] = j;
}
else j = next[j];
}
}
void get_nextval(String T, int *next)
{
int i=1,j=0;//i表示后缀,j表示前缀
next[1]=0;
while(i<T[0])
{
if( j==0 || T[i]==T[j])
{
++i;++j;
if(T[i]!=T[j]) next[i] = j;
else next[i] = next[j];
}
else j = next[j];
}
}
理解:next数组跟T等长,其实就是规定了在T串的第j个位置发生了不匹配,j要回退到哪里。如果T串j位置前没有重复的子串,j当然要退回到1,重新匹配,但这时i不用回退也知道这期间的字符不会匹配。如果j位置前存在重复子串,就需要按next指定的位置回退到指定位置。
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;
}