第四章-------------串
串
字符串是最基本的非数值数据,字符串是一种特定的线性表,其特殊性在于组成线性表的每个元素就是一个单字符。
串的存储结构
(1)定长顺序串:定长顺序存储表示:用一组地址连续的存储单元存储串值的字符序列
#define MaxSize 255//预定义最大串长为255 typedef struct { char ch[MaxSize];//每个分量存储一个字符 int length;//串的实际长度 }SString; //串的实际长度只能小于等于MaxSize,超过预定义长度的串值会被舍去,称为截断
//在串s中下标为pos的字符之前插入串t int StrInsert(SString* s, int pos, SString t) { int i; if (pos<0 || pos>s->length)//插入位置不合法 return (0); if (s->length + t.length <= MaxSize) {//插入后串长<=MaxSize for (i = s->length + t.length - 1; i >= t.length + pos; i--) s->ch[i] = s->ch[i - t.length]; for (i = 0; i < t.length; i++) s->ch[i + pos] = t.ch[i]; s->length = s->length + t.length; } else if (pos + t.length <= MaxSize) {//插入后串长>MaxSize,但串t的字符序列可以全部插入 for (i = MaxSize - 1; i > t.length + pos - 1; i--) s->ch[i] = s->ch[i-t.length]; for (i = 0; i < t.length; i++) s->ch[i + pos] = t.ch[i]; s->length = MaxSize; } else {//插入后串长>MaxSize,但串t的部分字符也要舍弃 for (i = 0; i < MaxSize - pos; i++) s->ch[i + pos] = t.ch[i]; s->length = MaxSize; } return (1); } //顺序串删除函数,在串s中删除从下标pos起len个字符 int StrDelete(SString* s, int pos, int len) { int i; if (pos<0 || pos>(s->length - len))//删除参数不合法 return (0); for (i = pos + len; i < s->length; i++) s->ch[i - len] = s->ch[i];//从pos+len开始至串依次向前移动,实现删除len个字符 s->length = s->length - len;//s串长减len return (1); } //串比较函数,若串s和t相等返回0,若s>t则返回正数,若s<t则返回负数 int StrCompare(SString s, SString t) { int i; for (i = 0; i < s.length && i < t.length; i++) if (s.ch[i] != t.ch[i]) return (s.ch[i] - t.ch[i]); return (s.length - t.length); }
(2)堆串:堆分配存储仍然是以一组地址连续的存储单元存放串值的字符序列,但它们的存储空间是在程序执行过程中动态分配得到的。
typedef struct { char* ch;//按串长分配存储区,ch指向串的基地址 int length;//串的长度 }HString;
//堆串删除字符串:删除字符串S中从pos位置开始的len长度子串 void StrDelete(HString* S, int pos, int len) { //判断是否不满足删除条件 if (pos<0 || pos>S->length) return; if (len <= 0 || len > S->length) return; int j = pos; //设置开始删除的位置 //将pos+len处及其之后的字符全部往前移动len长度,通过覆盖实现删除 for (int i = j + len; i < S->length; ++i) { S->ch[i - len] = S->ch[i]; } //修改删除后S的长度 S->length -= len; }
//在串s下标为pos的字符之前插入串t int StrInsertd(HString* s, int pos, HString* t) { int i; char* temp; if (pos < 0 || pos>s->length || s->length == 0)//插入位置不合法 return (0); temp = (char*)malloc(s->length + t->length);//动态产生足够的空间存放插入后的串 if (temp == NULL) return (0); for (i = 0; i > pos; i++) temp[i] = s->ch[i]; for (i = 0; i < t->length; i++) temp[i + pos] = t->ch[i]; for (i = pos; i < s->length; i++) temp[i + t->length] = s->ch[i]; s->length += t->length; free(s->ch); s->ch = temp; return(1); } //堆串赋值函数 int StrAssign(HString* s, char* tval) { //将字符串常量tval的值赋给堆串s int len, i = 0; if (s->ch != NULL) free(s->ch); while (tval[i] != '\0') i++; len = i; if (len) { s->ch = (char*)malloc(len); if (s->ch == NULL) return (0); for (i = 0; i < len; i++) s->ch[i] = tval[i]; } else s->ch = NULL; s->length = len; return(1); }
(3)块链串
typedef struct StringNode { char ch;//每个结点存一个字符 struct StringNode* next; }StringNode,*String; typedef struct Stringnode { char ch[4];//每个结点存四个字符 struct Stringnode* next; }Sstringnode,*Sstring;
简单模式匹配算法思想:从主串S的第pos个字符开始,和模式串T的第一个字符开始比较,如果相等,就继续比较后续字符,如果
不等,则从主串S的第pos+1个字符开始重新和模式串T比较,直到模式串T中的每个字符和主串S中的一个连续字符子序列全部相等,则称匹配成功,返回和T中第一个字符相等的字符在主串S中的位置;或者主串中没有和模式串相等的字符序列,则称匹配不成功。
实现时设i,j,start三个指示器:
i指向主串S中当前比较的字符,起始指向S的首字符,此后,每比较一步,后移一个位置,一趟匹配失败时,回溯到该趟比较起点的下一个位置。
j指向子串T中当前比较的字符,起始指向T的首字符,此后,每比较一步,后移一个位置,一趟匹配失败时,回溯到T的首字符处。
start记录每趟比较时在主串S中的起点,每趟比较后,后移一个位置,以便确定下一趟的起始位置。
//求主串S的下标pos起,串t第一次出现的位置,成功返回位置序号,不成功返回-1 int StrIndex(SString S,int pos, SString T) { int i, j,start; if (T.length == 0)//当模式串为空串时,是任意串的匹配串 return (0); start = pos; i = start; j = 0;//主串从pos开始,模式串从头(0)开始 while (i < S.length && j < T.length) { if (S.ch[i] == T.ch[j]) {//当前对应字符相等时推进 ++i; ++j; } else {//当前对应字符不等时回溯 start++; i = start;//主串从start+1开始,模式串从头(0)开始 j = 0; } } if (j >=T.length) return (start);//匹配成功时,返回匹配起始位置 else return -1;//匹配不成功时,返回-1 }
主串长度为n,模式串长度为m:
简单模式匹配最好的情况是每个子串的第一个字符就匹配失败O(n-m+1)=O(n)
简单模式匹配最坏的情况是每个子串都要对比m个字符,共n-m+1个子串,时间复杂度:O((n-m+1)*m)=O(nm)
努力的意义就是放眼望去以后都是喜欢的人和事......

浙公网安备 33010602011771号