本次实现的是串的顺序存储结构。
串的实现方式
串的实现方式可以分为3种。
① 定长顺序存储表示(本文的实现方式)
即固定大小
typedef struct {
char ch[MaxSize];
int length;
}SString;
②堆分配存储表示
即动态分配
typedef struct {
char *ch;
int length;
}HString;
③块链存储表示
typedef struct StringNode{
char ch[4]; //每个结点多存几个字符,提高存储密度
struct StringNode *next;
}StringNode,*String;
KMP理解
推荐一个KMP算法求next数组代码实现的讲解视频。
求next数组代码实现的讲解视频
code
#include <iostream>
using namespace std;
#define MaxSize 255
//采用定长顺序存储实现串
// ADT
//最小操作子集
// StrAssign(&T,chars) 赋值操作。把串T赋值为chars
// StrCompare(S,T) 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
// StrLength(S) 求串长。
// SubString(&Sub,S,pos,len) 求子串。用sub返回串S的第pos个字符起长度为len的子串
// Concat(&T,S1,S2) 串联接。用T返回由S1、S2连接而成的新串
//其他操作
// StrCopy(&T,S) 复制操作。由串S复制得到串T
// StrEmpty(S) 判空操作
// ClearString(S)清空操作。将串清为空串
// DestroyString(&S) 销毁串。将串S销毁
// Index(S,T) 定位操作。若子串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
// Index_KMP(S,T) 用KMP算法实现定位操作
typedef struct {
char ch[MaxSize];
int length;
}SString;
//最小操作子集
// 赋值操作。把串T赋值为chars
bool StrAssign(SString &T,char* chars);
// 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
int StrCompare(SString S,SString T);
// 求串长。
int StrLength(SString S);
// 求子串。用sub返回串S的第pos个字符起长度为len的子串
bool SubString(SString &Sub,SString S,int pos,int len);
// 串联接。用T返回由S1、S2连接而成的新串
bool Concat(SString &T,SString S1,SString S2);
//其他操作
// 求char*字符串长度
int CharsLength(char* chars);
// 输出串
void PrintString(SString S);
// 复制操作。由串S复制得到串T
bool StrCopy(SString &T,SString S);
// 判空操作
bool StrEmpty(SString S);
// 清空操作。将串清为空串
bool ClearString(SString S);
// 销毁串。将串S销毁
bool DestroyString(SString &S);
// 定位操作。若子串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
int Index(SString S,SString T);
// 用KMP算法实现定位操作
int IndexKMP(SString S,SString T);
// 用改进的KMP算法实现定位操作
int IndexKMPPlus(SString S,SString T);
// 求模式串T的next数组
void GetNext(SString T,int next[]);
// 求模式串T的next数组(改进算法)
void GetNextVal(SString T,int nextVal[]);
int main(){
char tmp1[]="abcd";
char tmp2[]="abce";
SString S1;
StrAssign(S1,tmp1);
SString S2;
StrAssign(S2,tmp2);
printf("S1:");
PrintString(S1);
printf("\n");
printf("S2:");
PrintString(S2);
printf("\n");
//比较
printf("比较结果:%d\n",StrCompare(S1,S2));
// 截取子串
SString sub;
SubString(sub,S1,2,3);
printf("sub:");
PrintString(sub);
printf("\n");
// 联结两个串为新串
SString concat;
Concat(concat,S1,S2);
printf("concat:");
PrintString(concat);
printf("\n");
// 定位
int idx=0;
idx=Index(S1,sub);
printf("定位结果:%d\n",idx);
// KMP定位
idx=IndexKMP(S1,sub);
printf("KMP定位结果:%d\n",idx);
idx=IndexKMPPlus(S1,sub);
printf("改进的KMP定位结果:%d\n",idx);
system("pause");
}
//最小操作子集
// 赋值操作。把串T赋值为chars
bool StrAssign(SString &T,char* chars){
if(CharsLength(chars)>MaxSize-1)//如果char字符数组大于MaxSize-1,则返回错误
return false; //(这里采用王道书上的方法,第零位不放元素,所以最多存储MaxSize-1个元素)
T.length=CharsLength(chars);
for(int i=1;i<=T.length;i++){
T.ch[i]=*(chars+i-1);
}
return true;
}
// 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
int StrCompare(SString S,SString T){
for(int i=1;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;
}
// 求串长。
int StrLength(SString S){
return S.length;
}
// 求子串。用sub返回串S的第pos个字符起长度为len的子串
bool SubString(SString &Sub,SString S,int pos,int len){
if(pos+len-1>S.length)
return false;
Sub.length=len;
for(int i=1;i<=len;i++)
Sub.ch[i]=S.ch[pos+i-1];
return true;
}
// 串联接。用T返回由S1、S2连接而成的新串
bool Concat(SString &T,SString S1,SString S2){
if(S1.length+S2.length>MaxSize-1)
return false;
T.length=S1.length+S2.length;
for(int i=1;i<=S1.length;i++){
T.ch[i]=S1.ch[i];
}
for(int i=1;i<=S2.length;i++){
T.ch[S2.length+i]=S2.ch[i];
}
return true;
}
//其他操作
// 求char*字符串长度
int CharsLength(char* chars){
int length=0;
while(chars[length]) length++;
return length;
}
// 输出串
void PrintString(SString S){
for(int i=1;i<=S.length;i++){
printf("%c",S.ch[i]);
}
}
// 复制操作。由串S复制得到串T
bool StrCopy(SString &T,SString S){
T.length=S.length;
for(int i=1;i<=S.length;i++){
T.ch[i]=S.ch[i];
}
return true;
}
// 判空操作
bool StrEmpty(SString S){
if(S.length==0) return true;
else return false;
}
// 清空操作。将串清为空串
bool ClearString(SString S){
S.length=0;
return true;
}
// 定位操作。若子串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
// 朴素算法
int Index(SString S,SString T){
int i=1,sl=S.length,tl=T.length;
SString sub;
while(i<=sl-tl+1){
SubString(sub,S,i,tl);
if(StrCompare(sub,T)!=0) i++;
else return i;
}
return 0;
}
// 用KMP算法实现定位操作
int IndexKMP(SString S,SString T){
int i=1,j=1;
int next[T.length+1];
GetNext(T,next);
while(i<=S.length&&j<=T.length){
if(j==0||S.ch[i]==T.ch[j]){
i++;
j++;//继续比较后继字符
}else{
j=next[j];//模式串向右移动
}
}
if(j>T.length)
return i-T.length;//匹配成功
else
return 0;//匹配失败
}
// 用改进的KMP算法实现定位操作
int IndexKMPPlus(SString S,SString T){
int i=1,j=1;
int nextVal[T.length+1];
GetNextVal(T,nextVal);
while(i<=S.length&&j<=T.length){
if(j==0||S.ch[i]==T.ch[j]){
i++;
j++;//继续比较后继字符
}else{
j=nextVal[j];//模式串向右移动
}
}
if(j>T.length)
return i-T.length;//匹配成功
else
return 0;//匹配失败
}
// 求模式串T的next数组
void GetNext(SString T,int next[]){
int i=1,j=0;
next[1]=0;
while(i<T.length){
if(j==0||T.ch[i]==T.ch[j]){
i++;j++;
next[i]=j;
}else{
j=next[j];
}
}
}
// 求模式串T的next数组(改进算法)
void GetNextVal(SString T,int nextVal[]){
int next[T.length+1];
GetNext(T,next);
nextVal[1]=0;
for(int i=2;i<=T.length;i++){
if(T.ch[next[i]]==T.ch[i])
nextVal[i]=nextVal[next[i]];
else
nextVal[i]=next[i];
}
}