目录
❀串及其运算
①串是由0个或多个字符组成的有序序列,一般记作S = "a1,a2,a3,...an",其中:
- ai可以是字母、数字或者其他字符,取决于程序设计语言所使用的字符集
- n为串中字符的个数,成为“串的长度”
串的一些常用术语:
- 空串(null string):长度为0的串,不包含任何字符
- 空格串(blank string):仅有一个或多个空格组成的串,空格串的长度大于等于1
- 子串(sub string):串中任意个连续字符组成的子序列,
- 主串(master string):包含“子串“的串,子串时主串的一部分
- 前缀子串(prefix sub string):前缀子串也是子串,记作:U = "a(1)...a(b)",(1=<b<=n)。当b<n时,相应的U称为S“真前缀子串”
- 后缀子串(suffic sub string):S的后缀子串也是子串,记作U = “a(n-b+1)...a(n)“(1<=b<=n)。当b<n时,相应的U称为S的“真后缀子串”
- 位置:将字符在串中的序号成为该字符在串中的位置,字串在主串中的位置以字串的第一个字符在主串中出现的位置来表示。
- 串相等:两个串等长且各自位置的字符相等
- 模式匹配:确定子串从主串的某个位置开始后,子串在主串中首次出现位置的计算
②串的运算
基本操作:
- StrAssign(S,chars) :生成一个串s,使其值等于chars
- StrCopy(S,T) : 将串T的值赋给串S
- StrLength(S) : 计算串S的长度
- StrInsert(S,pos,T) :在串S的第pos位置前插入串T
- StrDelete(S,pos,len):
初始条件:1<= pos <=strlen(S) && 0<= len <= strlen(S) - pos + 1;
结果:删除串S从第pos字符开始长度为len的字串- StrCompare(S,T):判断串S和T是否相等,相等返回0,不相等返回第一个不相等字符的ACSII码值之差
- StrCat(S,T):将串T的值连接在串S的后面
- SubString(T,S,pos,len):截取S中从第pos个字符开始长度为len个字符的字串赋值给串T
- StrIndex(S,pos,T):从S中第pos个字符开始判断是否有与串T相等的字串,若有,返回串T在S中首字符首次出现的位置,否则返回0
- StrReplace(S,T,V ):用串V替换串S中出现的所有与串T相同的字串
- StrEmpty(S):判断S是否为空,为空返回1,否则返回0
- StrClear(S):将S串清为空串
- StrDestory(S):销毁串S
❀串的存储结构及实现
串的实现方法有定长字符串,堆串和块链串。
❀定长顺序串
串的定长顺序存储结构指的是直接使用定长的字符数组来定义,为每一个串变量分配一个固定长度的存储区,存储分配是在编译时完成的。
❀定长顺序串存储结构
- 串的实际预设长度为MAXSIZE,如果串的长度超过MAXSIZE,串值会被舍弃,称为串的"截断"
- 为了操作方便,串定义中的第0个单元不使用
#define MAXSIZE <字符串的最大长度> typedef struct { char ch[MAXSIZE+1]; int len; }
❀基本操作
- 串插入函数
/*将串T插入到串S的第pos个字符之前*/ int SStrInsert(SString* s,int pos,const SString T) /* 1.插入后串的长度小于等于MAXSIZE,将pos后的字符后移T.length个位置,插入T 2.插入后串的长度大于MAXSIZE,且pos+T.length<=MAXSIZE,pos后的字符后移时,会有部分字符被舍弃 3.插入后串的长度大于MAXSIZE,qiepos+T.length>MAXSIZE,则pos后的字符全部被舍弃,T在插入时也有一部分字符被舍弃 */
int SStrInsert(SString* S,int pos,const SString T) { //插入之前检查插入的位置是否合理 if(pos<1 || pos>S->len+1) //可以在字符串的末尾插入 return 0; //第一种情况:S.length+T.length<=MAXSIZE if(S->len +T.len <=MAXSIZE) { for(int i=T.len+S->len;i>=pos+T.len;i--) S->ch[i] = S->ch[i-T.len]; for(int i=pos;i<pos+T.len;i++) S->ch[i] = T.ch[i-pos+1]; S->len += T.len; } //第二种情况:S.length+T.length>MAXSIZE,pos+T.length<=MAXSIZE else if(pos+T.len<=MAXSIZE) { for(int i=MAXSIZE;i>=pos+T.len;i--) S->ch[i] = S->ch[i-T.len]; for(int i=pos;i<pos+T.len;i++) S->ch[i] = T.ch[i-pos+1]; S->len += T.len; } //第三种情况:S.length+T.length>MAXSIZE && pos+T.length>MAXSIZE else { for(int i=pos;i<=MAXSIZE;i++) { S->ch[i] = T.ch[i-pos+1]; } S->len = MAXSIZE; } }
串删除函数
/*从串S中第pos个位置开始,删除长度为len的子串*/ int SStrDelete(SString* S,int pos,int len);
int SStrDelete(SString* S,int pos,int len) { //判断pos和len的位置合理性 if(pos<1 || pos>S->len || len<0 || len>S->len-pos+1) return 0; for(int i=pos;i<=S->len-len;i++) S->ch[i] = S->ch[i+len]; S->len -= len; return 1; }
串连接函数
/*将串T连接到串S的后面*/ int SStrCat(SString* S,const SString T); /* 1.S.length+T.length<=MAXSIZE,直接将T连接在S后面 2.S.length+T.length>MAXSIZE && S.length<MAXSIZE,则T在连接后会有部分字符被舍弃 3.S.length=MAXSIZE,则T的字符全部被舍弃,不用再连接 */
int SStrCat(SString* S,const SString T) { //第一种情况:S.length<MAXSIZE && S.length+T.length<=MAXSIZE if(S->len+T.len <= MAXSIZE) { for(int i=S->len+1;i<=S->len+T.len;i++) S->ch[i] = T.ch[i-S->len]; S->len += T.len; return 1; } //第二种情况 if(S->len<MAXSIZE) { for(int i=S->len+1;i<=MAXSIZE;i++) S->ch[i] = T.ch[i-S->len]; S->len = MAXSIZE; return 0; } //第三种情况 else { return 0; } }
求子串函数
/*从S中第pos个位置开始将长度为len的子串复制给T*/ int SubSString(SString* T,SString S,int pos,int len);
int SubSString(SString* T,SString S,int pos,int len) { //判断位置的合理性 if(pos<1 || pos>S->len || len<0 || len>S->len-pos+1) return 0; for(int i=1,i<=len;i++) T->ch[i] = S.ch[i+pos-1]; T->len = len; return 1; }
❀堆串
串的堆存储结构,与定长顺序串的存储结构类似,用一组地址连续的存储单元存储串的字符序列,不同的是堆串的存储结构实在程序运行过程中动态分配的。通常为了操作的方便,在实际串长的基础上多分配一个空间,连续空间的第0号单元不使用。
❀存储结构
typedef struct { char* ch; int len; }HString;
❀基本操作
1.串初始化函数
void HstrInit(HString* S) { S->ch = NULL; S->len = 0; }
2.串赋值函数
int HStrAssign(HString* s,const char* chars) { int i=0; while(char[i++]!='\0'); s->len = i; if(s->len != 0) { if(s->ch != NULL) free(s->ch); s->ch = (char*)malloc(sizeof(char)*(s->len+1)); if(!s->ch) return 0; for(i=1;i<=s->len;i++) s->ch[i] = chars[i-1]; } else s->ch = NULL;//空串 return 1; }
3.串插入函数
int HStrInsert(HString* s,int pos,const SString t) { int i = 0; //判断参数的合理性 if(pos<0 || pos>s->len) return 0; char* temp = (char*)malloc(sizeof(char)*(s->len+t.len+1)); if(!temp) return 0; for(i=1;i<pos;i++) temp[i] = s->ch[i]; for(i=pos;i<pos+t.len;i++) temp[i] = t.ch[i-pos+1]; for(i=pos+t.len;i<=s->len+t.len;i++) temp[i] = s->ch[i-t.len]; s->ch = temp; s->len += t.len; return 1; }
4.串删除函数
int HStrDelete(HStirng* s,int pos,int len) { int i = 0; //按断插入位置的合理性 if(len<0 || len>s->len-pos+1 || pos<1 || pos>s->len) return 0; char* temp = (char*)malloc(sizeof(char*)*s->len-len+1); if(!temp) return 0; for(i=1;i<pos;i++) temp[i] = s->ch[i]; for(i=pos;i<=s->len-len;i++) temp[i] = s->ch[i+len]; s->ch = temp; s->len -= len; return 1; }
5.串连接函数
int HStrCat(HString* s,const HString t) { int i=1; s->ch = (char*)realloc(s->ch,sizeof(char)*(s->len+t.len+1)); if(!s->ch) return 0; for(i=s->len+1;i<=s->len+t.len;i++) s->ch[i] = t.ch[i-s->len]; s->len += t.len; return 1; }
❀串的模式匹配
子串的定位操作是找子串在主串中从第pos个字符出现的位置,又称为“串的模式匹配”或“串匹配”。在串的模式匹配中,一般将主串称为S称为目标串,子串T称为模式串。
❀BF模式匹配算法
Brute-Force算法又称“蛮力匹配”算法。即从主串的第“pos”个字符开始,依次与模式串中的第一个字符进行比较,若相等,则继续逐个比较后续字符,否则回溯到主串的第“pos+1”个字符继续和模式串进行比较。以此类推,直至子串中的每一个字符与主串中的字符相等,则称模式匹配算法成功,返回串T的第一个字符在主串S中匹配成功的第一次出现的位置;否则,则称模式匹配失败。
BF算法描述:
Int BF_Index(SSreing s,int pos,SString t) { int i = pos;//主串从pos开始,模式串从首字符开始 int j = 1; while(i <= s->len && j <= t.len) { if(s->ch[i] == t.ch[i]) i++,j++; else { i = i - j + 2;//主串回溯到第pos+1个字符的位置处 j = 0;//模式串从头开始和目标串进行匹配 } } if(j > t.len) return i - t.len; return 0; //匹配失败 }