目录
一、串的存储结构
1、存储结构
//顺序存储
#define Maxsize 255
typedef struct {
char ch[Maxsize];
int length;
}SString;
//堆分配存储
typedef struct {
char* ch;
int length;
}HString;
//S.ch = (char*)malloc(sizeof(char) * Maxlen);
//块链存储
typedef struct StringNode {
char ch[4];
struct StringNode* next;
}StringNode,*String;
2、基本操作
bool SubString(SString &Sub, SString s, int pos, int len) {//求子串,用Sub返回串s的第Pos个字符起,长度为len的子串
if (pos + len - 1 > s.length)return false;
for (int i = pos; i < pos + len; i++)
Sub.ch[i - pos + 1] = s.ch[i];
Sub.length = len; //下标从1开始
return true;
}
int Index(SString S, SString T) {//若主串S中存在于T相同的子串,返回它在S中第一次出现的位置
int i = 1, n = S.length, m = T.length;
SString Sub;
while (i <= n - m + 1) {
SubString(Sub, S, i, m);//把从S中第i个字符起,长度为m的子串给Sub
if (StrCompare(Sub, T) != 0)++i;//比较
else return i;
}
return 0;
}
二、串的简单匹配模式
int Index(SString S, SString T) {//若主串S中存在于T相同的子串,返回它在S中第一次出现的位置
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;//S的指针指向下一个字符
j = 1;
}
}
if (j > T.length)return i - T.length;//找到了
else return 0;
}
主串长度为n,模式串长度为m,则最多对比n-m+1次。
最坏时间复杂度:O(n*m)
三、KMP
1、如何求next数组
next[j]含义:当子串的第j个字符与主串发生失配时,跳到子串的next[j]的位置重新与主串当前位置进行比较
next[1]=0
next[2]=1
步骤:
1.按下列列表列好,序号和模式串
2.假设当i指向3时,失配,那么我们需要将模式串往后移动,直到3之前的序列时相同的,那么此时j指向的值就是next[j]的值了
序号 | 1 | 2 | 3 | 4 | 5 | 6 |
模式串 | a | b | a | b | a | a |
next[i] | 0 | 1 | 1 | 2 | 3 | 4 |
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];
}
}
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;
}
时间复杂度为O(m+n)
注:若串的位序从1开始,则next数组才需要整体+1,若从0开始,不需要整体+1
2、进一步优化nextval
nextval[1]=0
步骤:
1.如下,当j指向3时,next[3]=1,那么我们找到j=1的字符,发现3所示字符和1所示字符相等,都是a,则把1所示字符的nextval值给3
2.而如果所示字符不等,例如j=6时,此时nextval=next
序号j | 1 | 2 | 3 | 4 | 5 | 6 |
模式串 | a | b | a | b | a | a |
next[j] | 0 | 1 | 1 | 2 | 3 | 4 |
nextval[j] | 0 | 1 | 0 | 1 | 0 | 4 |
void getNextval(SString T, int nextval[]) {
int i = 1, j = 0;
nextval[1] = 0;
while (i < T.length) {
if (j == 0 || T.ch[i] == T.ch[j]) {
i++; j++;
if (T.ch[i] != T.ch[j])nextval[i] = j;
else nextval[i] = nextval[j];
}
else
j = nextval[j];
}
}