# 原创 : 第四章 串 # 第四章 串 ## 一、串数据类型的定义 ### 1.定义和存储结构 ``` char str[]="abcdef"; //定长顺序存储 typedef struct { char str[maxSize+1];//加1是为了多出一个用来存储'\0'作为结束标记 int length; }Str; //变长分配存储 typedef struct { char *ch; int length; }Str; ``` ### 2.串的基本操作 ``` //1.赋值 int strassign(Str& str,char* ch) { if(str.ch)free(str.ch) //释放原数组空间 int len=0; char *c=ch; //c指向ch while(*c) //求串的长度 { ++len; ++c; } if(len==0) { str.ch=NULL; str.length=0; return 1; } else { str.ch=(char*)malloc(sizeof(char)*(len+1)); if(str.ch==NULL)return 0; else { c=ch; for(int i=0;i<=len;++i,++c)str.ch[i]=*c; str.length=len; return 1; } } } //strassign(str,"cur input") //2.取串的长度 int strlength(Str str) { return str.length; } //3.串比较操作 int strcompare(Str s1, Str s2) { for(int i;i<s1.length&&i<s2.length;++i) { if(s1.ch[i]!=s2.ch[i])return s1.ch[i]-s2.ch[i]; return s1.length-s2.length; } } //4.串连接操作 int concat(Str &str, Str str1, Str str2) { //如果str不为空,则释放str空间 //如果为空,则返回0,也就是不能进行串操作 if(str.ch) { free(str.ch); str.ch=NULL; } str.ch=(char*)malloc(sizeof(char)*(str1.length+str2.length+1)); if(str.ch==NULL)return 0; int i=0; while(i<str1.length) { str.ch[i]=str1.ch[i]; ++i; } int j; while(j<=str2.length) { str.ch[i+j]=str2.ch[j]; ++j; } str.length=str1.length+str2.length; return 1; } //5.求子串操作 //从pos处开始,长度为len的子串 int substring(Str& substr, Str str, ingt pos,int len) { if(pos<0||pos>=str.length||len<0||len>str.length-pos)return 0; if(substr.ch) { free(substr.ch); substr.ch=NULL; } if(len==0) { substr.ch=NULL; substr.length=0; return 1; } else { substr.ch=(char*)malloc(sizeof(char)*(len+1)); int i=pos; int j=0; while(i<pos+len) { substr.ch[j]=str.ch[i]; ++i; ++j; } substr.ch[j]='\0'; sunstr.length=len; return 1; } } //6.串清空操作 int clearstring(Str& str) { if(str.ch) { free(str.ch); str.ch=NULL; } str.length=0; return 1; } ``` ## 二、串的模式匹配算法 ### 1.简单模式匹配算法 ``` //对一个串中的定位操作称为串的模式匹配 //其中串中字符存放在1-length的位置上 int index(Str str,Str substr) { int i=1,j=1,k=i; while(i<=str.length&&j<=str.length) { if(str.ch[i]==substr.ch[j]) { ++i; ++j; } else { j=1; i=++k; } } if(j>substr.length)return k; else return 0; } ``` ### 2.KMP算法 ``` //思路:每当发生模式串不匹配的情况,先找出发生不匹配的字符pj,取其子串F=p1p2p3...Pj-1 //将模式串后移,使F最先发生前部(FL)和后部(FR)相重合的位置,即模式串后移的目标位置 //即j指向的F前后重合的子串的长度+1(FL和FR的长度加1),可以定义一个next[j]数组,取j=1~m //m为模式串长度,表示模式串中第j个字符发生不匹配时,应从next[j]处的字符开始重新发生与主串比较 //求next数组: //next[j]已知,t为当前F最长相等前后缀长度(即FL和FR的长度next[j]=t) //当pj=pt,则next[j+1]=t+1; //当pj!=pt,则t=next[t]; void getnext(Str substr, int next[]) { int j=1,t=0;next[1]=0; while(j<substr.length) { if(t==0||substr.ch[i]==substr.ch[t])next[++j]=++t; else t=next[t]; } } //得到next数组之后,可以将简单算法改进成著名的KMP算法 int KMP(Str str, Str substr, int next[]) { //假设从下标为1开始存储的字符 int i=1, j=1; while(i<=str.length&&j<=substr.length) { if(j==0||str.ch[i]==substr.ch[j]) { ++i; ++j; } else j=next[j]; } if(j>substr.length)retrun i-substr.length; else return 0; } ``` ### 3.KMP算法的改进 ``` //当j=1时,nextva[j]=0,作为特殊标记 //pj!=pk时,nextval[j]=next[j]=k; //pj=pk时,nextval[j]=nextval[next[j]]=nextval[k]; void getnextval(Str substr,int nextval[]) { int i=1,j=0; nextval[1]=0; while(i<substr.length) { if(j==0||substr.ch[i]==substr.ch[j]) { ++i; ++j; // 加了这两句 if(substr.ch[i]!=substr.ch[j])nextval[i]=j; else nextval[i]=nextval[j]; } else j=nextval[j]; } } ```