知识要点:
串的基本概念、串的存储结构和相关的操作算法;
数组的存储结构,在顺序存储的情况下,数组元素与存储单元的对应关系;
稀疏矩阵的存储结构和特点以及基本操作。
字符串匹配算法(例如KMP算法)。
串的定义:由一个或多个字符组成的有限序列;内字符的个数称之为串的长度,字符个数为0的称之为空串。
串的比较:1)长度相同 2)对应位置上的元素也相同;
重点 串的模式匹配算法:
1、暴力匹配算法(BF):
特点:主串与模式串的指针在发生不匹配时都发生回溯现象(主串回到上一次匹配位置的下一个位置,模式串回到起始位置);
int BF(char a[],char b[]){
int i=0,j=0;
while(i=strlen(b)){
return i-strlen(b);//返回匹配成功的第一个位置
}
return -1;//匹配失败
}
算法时间复杂度:时间复杂度为O(mn),一般情况下O(m+n)为线性阶;
2、KMP算法(重点掌握next数组的计算):
特点:主串指针不发生回溯现象,模式串指针回溯
☆☆☆next数组的求解以及KMP算法代码
void getnext(char b[]){ //next数组的计算
int i=0,j=-1;
next[0]=-1; //初始化next[0]=-1
while(i=strlen(b)){
return i-strlen(b); //返回最先发生匹配的位置
}
return -1; //匹配失败
}
算法解析:(实现模式串的最大移动,减少重复的比较次数)S为主串,T为模式串
假设主串中第i个字符与模式串中的第j个字符发生了失配现象,模式串中的j要回到k位置处重新与主串中第i个位置进行比较
在0--k中必有k-1个字符与主串中的第i位之前的k-1个字符相互匹配,即S[i-k+1,i-1]=T[1,k-1]
在j处发生失配则向前的k-1位必然也与主串相互匹配,即S[i-k+1,i-1]=T[i-j+1,j-1]
有上述两式子得出,模式串回到的位置k与主串无关,且分别为长度相同的前缀串和后缀串(长度为k-1)而模式串所要回到
的位置k即为此串长度+1(即:最大前缀与后缀公共子串长度加一)
举个例子: 初始化:next[1]=0;//固定要求
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
模式串 | a | b | a | a | b | c | a | c |
next[j] | 0 | 1 | 1 | 2 | 2 | 3 | 1 | 2 |
next数组第一位置0;//固定要求
第二位 无前缀和后缀公共子串记长度为0,则next[2]=1;
第三位 无前缀和后缀公共子串记长度为0,则next[3]=1;
第四位 有前缀和后缀公共子串a,长度为1,则next[4]=2;
第五位 有前缀和后缀公共子串a,长度为1,则next[5]=2;
第六位 有前缀和后缀公共子串ab,长度为2,则next[6]=3;
第七位 无前缀和后缀公共子串记长度为0,则next[7]=1;
第八位 有前缀和后缀公共子串a,长度为1,则next[8]=2;
总结:next数组求解就是找此位置之前的串中最长的匹配前后缀子串,其长度加一就是该位置next数组的值;
3、优化的KMP算法(修正next数组,避免重复匹配):
特点:主串指针不发生回溯现象,模式串指针回溯,在KML算法中进行了优化处理;
j | 1 | 2 | 3 | 4 | 5 |
模式串 | a | a | a | a | b |
next[j] | 0 | 1 | 2 | 3 | 4 |
nextval[j] | 0 | 0 | 0 | 0 | 4 |
对于next数组的求解同上;发现在2-4位置都发生了重复匹配的现象,即在2-4任意溢出匹配失败next数组都回到了前一位置
但理论上回到最初的位置重新比较最好,过程中产生了多次的重复比较。
如果下一个位置元素与此位置元素相同则此位置next数组的值与上一个位置的next数组的值相同,反之遵循普通next数组的
求解方式。
☆☆☆nextval数组的求解
void getnextval(char b[]){
int i=0,j=-1;
next[0]=-1;
while(i
数组的存储结构(一般是申请一个固定大小的内存空间,不进行插入或者删除操作)
假设每一个数据元素占用L个存储单元,则二维数组A[0..m-1,0..n-1]中任意一个元素的存储位置为
Loc[a(i,j)]=Loc[a(0,0)]+(n*i+j)*L;((数单元格数-1)乘空间大小加上起始地址)
3、特殊矩阵的压缩问题(三角矩阵、稀疏矩阵、对称矩阵)
1、对称矩阵 (矩阵等于矩阵的转置)对应元素a(i,j)=a(j,i)
若保存全部元素则需要n*n个存储单元,但是由性质得出只需要保存一半,另一半可由性质推出,可将n*n个存储单元压缩至
n*(n+1)/2个存储单元中;
二维矩阵(i,j)和一维数组下标k的对应关系为(下标都从0开始)
按照列优先的标准:k=i(i-1)/2+j-1 (i>=j);下三角
按照行优先的标准:k=j(j-1)/2+i-1 (i 2、三角矩阵 上三角矩阵:(i-1)(2n-i+2)/2+j-i;(j<=i);上三角 下三角矩阵:k=i(i-1)/2+j-1 (i>=j);下三角; 3、稀疏矩阵(元素个数非常少):常见的有对角矩阵、三对角矩阵; 注:矩阵的使用常和图的算法相互考察,计算矩阵中元素对应于数组中的位置就是根据行或者列的优先存取顺序,数该元素位于矩阵中的第几个位置减去1就是该元素对应一维数组中的位置k; 4、广义表(非重点) 定义:线性表的推广可以存取广义表,元素等; A=()定义空表,即表中元素为0;特殊的C=(())此广义表不为空表,长度为1; B=(e)定义为单原子表,长度为1; E=(a,E)是一个无限递归表,长度为2; 广义表的特点(结论) 1)广义表的元素可以为子表; 2)广义表可以被奇它广义表共享; 3)广义表可以是一个递归表; 广义表的操作:取表头getHead:获取非空广义表的第一个元素(可以为表也可以为单原子) 取表尾getRear:去除非空广义表的第一个元素,剩余的部分(一定是一个广义表) 广义表的深度Deap:最大子表深度+1; 广义表的长度Length:广义表中元素的个数;