tips:本文讲述串的模式匹配算法、KMP模式匹配算法、改进后的KMP模式匹配算法!!!
目录
串的模式匹配算法
子串的定位操作通常称为串的模式匹配。
1. 朴素的模式匹配算法
1.1 定义
这是最简单的模式匹配,即暴力匹配算法。
从主串S的第一个字符起,与模式串T的第一个字符比较。若相等,则继续逐个比较后续字符;若不相等,则从主串的下一个字符起,重新和模式串的所有字符比较。
以此类推,直到模式串T中的每个字符依次与主串S中的一个连续的字符序列(子串)相等,则匹配成功,函数返回模式串T首字符在主串S中的位置。否则匹配失败,函数返回值为0.
1.2 原理
1.3 实现代码
/* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */
/* 朴素的模式匹配法 */
int Index(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (S[i] == T[j]) /* 两字母相等则继续 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
{
i = i - j + 2; /* i退回到上次匹配首位的下一位 *///i=i-(j-1)+1
j = 1; /* j退回到子串T的首位 */
}
}
if (j > T[0]) //循环结束后,指针j超出T串的范围则成功(j会比T[0]大1)
{
return i - T[0]; //返回子串(受字符)在主串中的位置
}
else
{
return 0;
}
}
其中, 每次匹配失败后,指针 i 回退到上一次匹配首位的下一位 的代码:
i = i - j +2 是如何得来的呢?
i = i - j + 2 其实是 i = i - ( j - 1 ) + 1 的简化。
1.4 完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
typedef char String[MAXSIZE + 1]; /* 0号单元存放串的长度 */
/* 生成一个其值等于chars的串T */
Status StrAssign(String T, char* chars)
{
int i;
if (strlen(chars) > MAXSIZE)
{
return ERROR;
}
else
{
T[0] = strlen(chars);
for (i = 1; i <= T[0]; i++)
{
T[i] = *(chars + i - 1);
}
return OK;
}
}
Status ClearString(String S)
{
S[0] = 0;/* 令串长为零 */
return OK;
}
/* 输出字符串T。 */
void StrPrint(String T)
{
int i;
for (i = 1; i <= T[0]; i++)
{
printf("%c", T[i]);
}
printf("\n");
}
/* 返回串的元素个数 */
int StrLength(String S)
{
return S[0];
}
/* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */
/* 朴素的模式匹配法 */
int Index(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (S[i] == T[j]) /* 两字母相等则继续 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
{
i = i - j + 2; /* i退回到上次匹配首位的下一位 *///i=i-(j-1)+1
j = 1; /* j退回到子串T的首位 */
}
}
if (j > T[0]) //循环结束后,指针j超出T串的范围则成功(j会比T[0]大1)
{
return i - T[0]; //返回子串(受字符)在主串中的位置
}
else
{
return 0;
}
}
void test01()
{
String s1, s2;
StrAssign(s1, "goodgoogle");
StrAssign(s2, "google");
//index
int pos = 1;
int i_index = Index(s1, s2, pos);
printf("子串s2在主串s1中第%d个字符之后的位置是(0表示不存在):%d\n", pos, i_index);
//子串s2在主串s1中第1个字符之后的位置是(0表示不存在):5
}
int main()
{
test01();
return 0;
}
2.KMP模式匹配算法
2.1 定义
朴素模式匹配算中指针 i 与 指针 j 会不断回退再进行比较,时间复杂度为O((n-m+1)*m),n为主串长度,m为模式串长度。
为了改进朴素模式匹配算法低效率的缺点,D.E.Knuth、J.H.Morris 和 V.R.Partt 三位前辈发表了一个模式匹配算法,可以大大避免重复遍历的情况,我们把它称之为 克努特-莫里斯-普拉特算法,简称KMP算法。
匹配失败后,指针 i 线性往前递增,指针 j 则进行回溯,时间复杂度为O(n+m)算法效率大大提高。
2.2 原理
2.2.1 前缀 、 后缀、 最大相等前后缀
前缀:指除最后一个字符以外,字符串的所有头部子串 ;
后缀:指除第一个字符以外字符串所有的尾部子串;
最大相等前后缀:字符串前缀和后缀的最长相等前后缀的长度。
例子:子串“ababa”
前缀:{a,ab,aba,abab}
后缀:{a,ba,aba,baba}
最大相等前后缀:{a,aba}
2.2.2 基于朴素模式匹配算法的改进
在上面朴素的模式匹配算法中有两种情况是可以简化步骤的。
情况一:在已匹配的字符中,子串中无最大相等前后缀(子串首位字符与后面其余字符均不相等时)。
情况二:在已匹配的字符中,子串有最大相等前后缀时。
可以发现,在之前朴素模式匹配算法中,主串的i值是不断地回溯来完成的,而这种回溯是可以省略的。
即匹配失败后指针 i 不变,指针 j 会跳转到一个特定的值。而这个特定的值 取决于 当前位置前子串的最大相等前后缀。
把模式串T的各个位置的变化定义为一个数组next(存放在数组next中)。
2.2.3 next数组值的推导
next[j] = 当前位置前的子串的最大相等前后缀的长度 + 1
注意:规定 j = 1 时, next [ j ] = 0 。
2.2.4 示例
主串:“abcddabcab”
模式串:“abcab”
- 先推导出模式串串的next数组
主串和模式串串从首位字符开始比较,指针i 指向主串S当前比较字符, 指针 j 指向模式串T当前比较位置。
如果当前比较字符相等,i++, j++; 如果不相等,指针i 不变, 指针j 跳转的 next[j] 的位置,继续比较。
并且当指针 j 为0 时,指针 i 与 指针j 同时加1。(即若主串的第i 个位置,与模式串的第一个字符不等时,则应从主串的第 i + 1个位置开始匹配。)
2.3 KMP模式算法的实现
2.3.1 求next数组值
/* 通过计算返回子串T的next数组。 */
//求next数组
void get_next(String T, int* next)
{
int i = 1;
int k = 0;
next[1] = 0; //同时隐含规定你next[2]=1
while (i < T[0]) //T[0]为串T的长度
{
if (k == 0 || T[i] == T[k])
{
++i;
++k;
next[i] = k; //k指向的位置 即最前相等前后缀 中 前缀的后一位
//当指针i和指针K指向的字符相等时,这两个字符就构成了 一个相等前后缀,长度记为k,
//经过++i,++k 将k+1存放在下一个i指向的next[]里
//所以next[k]永远存放 当前位置之前的 最长相等前后缀的长度
}
else
{
k = next[k]; //next[k]中记录着之前最长相等前后缀的长度
//k = next[k], 从当前的最长相等前后缀的长度(k) 返回 之前的最长相等前后缀的长度(next[k]),继续循环比较,
}
}
}
2.3.2 模式匹配(KMP)
/* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */
/* T非空,1≤pos≤StrLength(S)。 */
int Index_KMP(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
int next[255]; /* 定义一next数组 */
get_next(T, next); /* 对串T作分析,得到next数组 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (j==0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */
{
++i;
++j;
}
else
{ /* 指针后退重新开始匹配 */
j = next[j]; //与朴素的模式匹配算法相比
//kmp模式匹配算法 匹配失败后
// 指针i不变,指针j 回溯到特定的值 next[j]
}
}
if (j > T[0])
{
return i-T[0]; //T存在于S中,返回模式串T在主串S中的起始位置
}
else
{
return 0; //不存在
}
}
2.4 完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
typedef char String[MAXSIZE + 1]; /* 0号单元存放串的长度 */
/* 生成一个其值等于chars的串T */
Status StrAssign(String T, char* chars)
{
int i;
if (strlen(chars) > MAXSIZE)
{
return ERROR;
}
else
{
T[0] = strlen(chars);
for (i = 1; i <= T[0]; i++)
{
T[i] = *(chars + i - 1);
}
return OK;
}
}
//清空串
Status ClearString(String S)
{
S[0] = 0;/* 令串长为零 */
return OK;
}
/* 输出字符串T。 */
void StrPrint(String T)
{
int i;
for (i = 1; i <= T[0]; i++)
{
printf("%c", T[i]);
}
printf("\n");
}
/* 输出Next数组值。 */
void NextPrint(int next[], int length)
{
int i;
for (i = 1; i <= length; i++)
{
printf("%d", next[i]);
}
printf("\n");
}
/* 返回串的元素个数 */
int StrLength(String S)
{
return S[0];
}
/* 朴素的模式匹配法 */
int Index(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (S[i] == T[j]) /* 两字母相等则继续 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
{
i = i - j + 2; /* i退回到上次匹配首位的下一位 */
j = 1; /* j退回到子串T的首位 */
}
}
if (j > T[0])
{
return i - T[0];
}
else
{
return 0;
}
}
//求next数组
void get_next(String T, int* next)
{
int i = 1;
int k = 0;
next[1] = 0; //同时隐含规定你next[2]=1
while (i < T[0]) //T[0]为串T的长度
{
if (k == 0 || T[i] == T[k])
{
++i;
++k;
next[i] = k; //k指向的位置 即最前相等前后缀 中 前缀的后一位
//当指针i和指针K指向的字符相等时,这两个字符就构成了 一个相等前后缀,长度记为k,
//经过++i,++k 将k+1存放在下一个i指向的next[]里
}
else
{
k = next[k]; //next[k]中记录着之前最长相等前后缀的长度
//k = next[k], 从当前的最长相等前后缀的长度(k) 返回 之前的最长相等前后缀的长度(next[k])
}
}
}
/* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */
/* T非空,1≤pos≤StrLength(S)。 */
int Index_KMP(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
int next[255]; /* 定义一next数组 */
get_next(T, next); /* 对串T作分析,得到next数组 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (j == 0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */
{
++i;
++j;
}
else
{
/* 指针后退重新开始匹配 */
j = next[j];/* j退回合适的位置,i值不变 */
}
}
if (j > T[0])
{
return i - T[0];
}
else
{
return 0;
}
}
/* 求模式串T的next函数修正值并存入数组nextval */
void get_nextval(String T, int* nextval)
{
int i, k;
i = 1;
k = 0;
nextval[1] = 0;
while (i < T[0]) /* 此处T[0]表示串T的长度 */
{
if (k == 0 || T[i] == T[k]) /* T[i]表示后缀的单个字符,T[k]表示前缀的单个字符 */
{
++i;
++k;
if (T[i] != T[k])
{
/* 若当前字符与前缀字符不同 */
nextval[i] = k; /* 则当前的k为nextval在i位置的值 */
}
else
{
nextval[i] = nextval[k]; /* 如果与前缀字符相同,则将前缀字符的 */
/* nextval值赋值给nextval在i位置的值 */
}
}
else
{
k = nextval[k]; /* 若字符不相同,则k值回溯 */
}
}
}
int Index_KMP1(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
int next[255]; /* 定义一next数组 */
get_nextval(T, next); /* 对串T作分析,得到next数组 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (j == 0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
j = next[j];/* j退回合适的位置,i值不变 */
}
if (j > T[0])
return i - T[0];
else
return 0;
}
void test01()
{
String s, t;
//主串
StrAssign(s, "abcddabcab");
StrPrint(s); //abcddabcab
//子串
StrAssign(t, "abcab");
StrPrint(t); //abcab
//子串next
int i = StrLength(t); //子串的长度
int* p = (int*)malloc((i + 1) * sizeof(int)); //开辟存放子串next值的数组空间,长度与子串长度相同
get_next(t, p);
//next值
NextPrint(p, StrLength(t)); //01112
//index_kmp
int i_index = Index_KMP(s, t, 1);
printf("%d", i_index); //6
}
void test02()
{
String s, t;
//主串
StrAssign(s, "abcabaaaab");
StrPrint(s); //abcddabcab
//子串
StrAssign(t, "abaaaab");
StrPrint(t); //abaaaab
//子串nextval
int i = StrLength(t); //子串的长度
int* p = (int*)malloc((i + 1) * sizeof(int)); //开辟存放子串next值的数组空间,长度与子串长度相同
get_nextval(t, p);
//next值
NextPrint(p, StrLength(t)); //0102221
//index_kmp1
int i_index = Index_KMP1(s, t, 1);
printf("%d", i_index); //4
}
int main()
{
//test01();
test02();
return 0;
}
3. KMP模式匹配算法的改进
3.1 KMP算法的缺陷
例如:
主串S = “aaaabcde”
模式串T = “aaaaax”
由于串T的第二、三、四、五位置的字符都与 首位字符“a”相等,那么可以跳过上面的2、3、4、5步骤,即直接用首位next[1] 的值去取代与它相等的字符后续next[j]的值。
3.2 nextval数组的推导
/* 求模式串T的next函数修正值并存入数组nextval */
void get_nextval(String T, int* nextval)
{
int i, k;
i = 1;
k = 0;
nextval[1] = 0;
while (i < T[0]) /* 此处T[0]表示串T的长度 */
{
if (k == 0 || T[i] == T[k]) /* T[i]表示后缀的单个字符,T[k]表示前缀的单个字符 */
{
++i;
++k;
if (T[i] != T[k])
{
/* 若当前字符与前缀字符不同 */
nextval[i] = k; /* 则当前的k为nextval在i位置的值 */
}
else
{
nextval[i] = nextval[k]; /* 如果与前缀字符相同,则将前缀字符的 */
/* nextval值赋值给nextval在i位置的值 */
}
}
else
{
k = nextval[k]; /* 若字符不相同,则k值回溯 */
}
}
}
例如:
模式串T“ababaaaba”
先算出next数组的值,在分别进行判断。
- 当 j = 1 时,nextval[1] = 0;
- 当 j = 2 时, 第2位的字符“b”的next值是1,而其指向的next ,就是第1位“a”,它们不相等, 所以nextval[2] = next[2] =1;(k = next[k])
- 当 j = 3 时,第3为字符“a”的next值是1 , 所以与第1位字符“a”比较,相等,所以nextval[3] = nextval[1] = 0 ;(nextval[i] = nextval[k])
- 当 j = 4 时,第4位的字符“b”next值为2, 所以与第2位字符“b”相比较,相等,所以nextval[4] = nextval[2] = 1;
- 当 j = 5 时, next值为3, 第5个字符“a”与第3个字符“a”比较,相等,nextval[5] = nextval[3] = 0;
- 当 j = 6 时, next值为4, 第6个字符“a”与第4个字符“b”比较,不相等,nextval[6] = 4;
- 当 j = 7 时, next值为2, 第7个字符“a”与第2个字符“b”比较,不相等,nextval[7] = 2;
- 当 j = 8 时,next值为2, 第8个字符“b”与第2个字符“b”比较,相等,nextval[8] = nextval[2] = 1;
- 当 j = 9 时,next值为3, 第9个字符“a”与第3个字符“a”比较,相等,nextval[9] = nextval[3] = 1;
3.3 改进后的KMP模式匹配算法
与改进前的算法一样
int Index_KMP1(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
int next[255]; /* 定义一next数组 */
get_nextval(T, next); /* 对串T作分析,得到next数组 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (j == 0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
j = next[j];/* j退回合适的位置,i值不变 */
}
if (j > T[0])
return i - T[0];
else
return 0;
}
3.4 完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
typedef char String[MAXSIZE + 1]; /* 0号单元存放串的长度 */
/* 生成一个其值等于chars的串T */
Status StrAssign(String T, char* chars)
{
int i;
if (strlen(chars) > MAXSIZE)
{
return ERROR;
}
else
{
T[0] = strlen(chars);
for (i = 1; i <= T[0]; i++)
{
T[i] = *(chars + i - 1);
}
return OK;
}
}
//清空串
Status ClearString(String S)
{
S[0] = 0;/* 令串长为零 */
return OK;
}
/* 输出字符串T。 */
void StrPrint(String T)
{
int i;
for (i = 1; i <= T[0]; i++)
{
printf("%c", T[i]);
}
printf("\n");
}
/* 输出Next数组值。 */
void NextPrint(int next[], int length)
{
int i;
for (i = 1; i <= length; i++)
{
printf("%d", next[i]);
}
printf("\n");
}
/* 返回串的元素个数 */
int StrLength(String S)
{
return S[0];
}
/* 朴素的模式匹配法 */
int Index(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (S[i] == T[j]) /* 两字母相等则继续 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
{
i = i - j + 2; /* i退回到上次匹配首位的下一位 */
j = 1; /* j退回到子串T的首位 */
}
}
if (j > T[0])
{
return i - T[0];
}
else
{
return 0;
}
}
//求next数组
void get_next(String T, int* next)
{
int i = 1;
int k = 0;
next[1] = 0; //同时隐含规定你next[2]=1
while (i < T[0]) //T[0]为串T的长度
{
if (k == 0 || T[i] == T[k])
{
++i;
++k;
next[i] = k; //k指向的位置 即最前相等前后缀 中 前缀的后一位
//当指针i和指针K指向的字符相等时,这两个字符就构成了 一个相等前后缀,长度记为k,
//经过++i,++k 将k+1存放在下一个i指向的next[]里
}
else
{
k = next[k]; //next[k]中记录着之前最长相等前后缀的长度
//k = next[k], 从当前的最长相等前后缀的长度(k) 返回 之前的最长相等前后缀的长度(next[k])
}
}
}
/* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */
/* T非空,1≤pos≤StrLength(S)。 */
int Index_KMP(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
int next[255]; /* 定义一next数组 */
get_next(T, next); /* 对串T作分析,得到next数组 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (j == 0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */
{
++i;
++j;
}
else
{
/* 指针后退重新开始匹配 */
j = next[j];/* j退回合适的位置,i值不变 */
}
}
if (j > T[0])
{
return i - T[0];
}
else
{
return 0;
}
}
/* 求模式串T的next函数修正值并存入数组nextval */
void get_nextval(String T, int* nextval)
{
int i, k;
i = 1;
k = 0;
nextval[1] = 0;
while (i < T[0]) /* 此处T[0]表示串T的长度 */
{
if (k == 0 || T[i] == T[k]) /* T[i]表示后缀的单个字符,T[k]表示前缀的单个字符 */
{
++i;
++k;
if (T[i] != T[k])
{
/* 若当前字符与前缀字符不同 */
nextval[i] = k; /* 则当前的k为nextval在i位置的值 */
}
else
{
nextval[i] = nextval[k]; /* 如果与前缀字符相同,则将前缀字符的 */
/* nextval值赋值给nextval在i位置的值 */
}
}
else
{
k = nextval[k]; /* 若字符不相同,则k值回溯 */
}
}
}
int Index_KMP1(String S, String T, int pos)
{
int i = pos; /* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int j = 1; /* j用于子串T中当前位置下标值 */
int next[255]; /* 定义一next数组 */
get_nextval(T, next); /* 对串T作分析,得到next数组 */
while (i <= S[0] && j <= T[0]) /* 若i小于S的长度并且j小于T的长度时,循环继续 */
{
if (j == 0 || S[i] == T[j]) /* 两字母相等则继续,与朴素算法增加了j=0判断 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
j = next[j];/* j退回合适的位置,i值不变 */
}
if (j > T[0])
return i - T[0];
else
return 0;
}
void test01()
{
String s, t;
//主串
StrAssign(s, "abcddabcab");
StrPrint(s); //abcddabcab
//子串
StrAssign(t, "abcab");
StrPrint(t); //abcab
//子串next
int i = StrLength(t); //子串的长度
int* p = (int*)malloc((i + 1) * sizeof(int)); //开辟存放子串next值的数组空间,长度与子串长度相同
get_next(t, p);
//next值
NextPrint(p, StrLength(t)); //01112
//index_kmp
int i_index = Index_KMP(s, t, 1);
printf("%d", i_index); //6
}
void test02()
{
String s, t;
//主串
StrAssign(s, "abcabaaaab");
StrPrint(s); //abcddabcab
//子串
StrAssign(t, "abaaaab");
StrPrint(t); //abaaaab
//子串nextval
int i = StrLength(t); //子串的长度
int* p = (int*)malloc((i + 1) * sizeof(int)); //开辟存放子串next值的数组空间,长度与子串长度相同
get_nextval(t, p);
//next值
NextPrint(p, StrLength(t)); //0102221
//index_kmp1
int i_index = Index_KMP1(s, t, 1);
printf("%d", i_index); //4
}
int main()
{
//test01();
test02();
return 0;
}