一,串
-
串的定义
串(String)是由零个或多个字符组成的有限序列。一般记为S=a1a2…an(n≥0)。
- 子串:一个串中任意个连续的字符组成的子序列称为该串的子串(包含空串)。包含子串的串称为主串。子串在主串中的位置是由子串的第一个字符在主串中的位置决定的。
真子串是不包含自身的子串。 - 空格串是由一个或多个空格组成的串。空格串不是空串。
- 串的长度:指该串中字符的个数(包括空格)。空串的长度为0。
- 子串:一个串中任意个连续的字符组成的子序列称为该串的子串(包含空串)。包含子串的串称为主串。子串在主串中的位置是由子串的第一个字符在主串中的位置决定的。
-
串的基本操作
Strlen(T) 求串T的长度 Concat(T1,T2) 串连接 Substr(S,pos,len) 求子串 Index(S,T) 求子串T在主串S中的位置 Replace(S,T,V) 用V替换主串S中出现的所有子串T Strlength(S) 求串S的长度 StrInsert(S,pos,T) 在主串S的第pos个字符位置插入串T StrDelete(S,pos,len) 从主串S中删除第pos个字符起长度为len的子串 StrCopy(T,S) 复制串S到串T StrCompare(S,T) 比较串S和串T
-
串的存储结构
- 顺序存储
- 串的顺序存储结构
#define MAXLEN 255 typedef struct{ char ch[MAXLEN+1]; //存储串的字符数组,下表为0-255,0经常闲置不用 int length; //串的当前长度 }SString;//顺序字符串
- 链式存储
- 优点:操作方便
- 缺点:存储密度低,每个结点要存储指针域和字符域,指针域占用的空间较多
- 改进:将多个字符放在一个结点中,每个结点存储多个字符和指针域,指针域指向下一个结点
- 块链存储
#define MAXBLOCKSIZE 255 typedef struct Block{ char data[MAXBLOCKSIZE]; struct Block *next; }Block; typedef struct{ Block *head,*tail; //头指针和尾指针 int curlen; //当前串的长度 }LString;
- 顺序存储
-
串的模式匹配算法
-
目的:
在主串中找到第一个与模式串匹配的子串(即模式匹配) -
BF算法(简单匹配,穷举法)
- 算法代码:
#include<stdio.h> #include<string.h> int Index_BF(SString S,SString T){ int i=1,j=1; while(i<=S.length&&j<=T.length){ if(S.ch[i]==T.ch[j]){ ++i; ++j; }else{ i=i-j+2;//回溯到下一匹配 j=1; } } if(j>T.length) return i-T.length;//返回第一个匹配字符的下标 else return 0; }
- 算法时间复杂度
- 算法时间复杂度
- 算法代码:
-
KMP算法(链接KMP算法)
-
上图解释:看门牌算法:如果不成立,比如j=6时不成立,则看4,,不成立则看2,,不成立则看1.
+ 算法理解:最长前缀部分移至后缀部分,找前后缀时不包含不匹配的那一项,移动时只研究模式串(子串),模式串从数组下标1开始。最大前后缀长度+1为比较的部分。
+ 算法代码:
```c
int Index_KMP(SString S,SString T,int next[]){
int i=1,j=1;
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;
}
void get_next(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];
}
}
}
```
+ 算法时间复杂度
主串的指针不需要回溯,提速到O(m+n)
+ KMP算法的改进
二,数组
-
声明格式:数据类型 变量名称[行数][列数]
-
数组的抽象数组类型定义
例:二维数组的抽象数据对象和数据关系n=2(维数为2,二维数组),b1为第一维长度(行数),b2为第二维长度(列数),a为二维数组,a[i][j]为二维数组中第i行第j列的元素 -
基本操作
InitArray(&A,n);//初始化数组A DestroyArray(&A);//销毁数组A LocateElem(A,e,&i,&j);//查找元素e在数组A中的位置 GetElem(A,i,j,&e);//获取数组A中第i行第j列的元素 PutElem(A,i,j,e);//将元素e放入数组A中第i行第j列 IsFull(A);//判断数组A是否已满 IsEmpty(A);//判断数组A是否为空
三,广义表
-
广义表的定义:
广义表是n>=0个元素的有限序列,其中每个元素都是原子或者子表。原子是单元素,子表是广义表。广义表记作:LS=(a1,a2,…,an).一般大写字母表示广义表,小写字母表示原子。表头:LS的原子a1,表尾:LS中除了表头以外的部分构成的子表。
-
广义表的长度为最外层元素的个数
广义表的深度定义为:广义表中最大元素的层数(括号的层数)。例如:A=(a,(b,c,d)),A的长度为2,深度为2。原子的深度为0,空表的深度为1.