/**
* 实验题目:
* 利用KMP算法求子串在主串中出现的次数
* 实验目的:
* 深入掌握KMP算法的应用
* 实验内容:
* 利用KMP算法求子串t在主串s中出现的次数,并以s="aaabbdaabbde",
* t="aabbd"为例显示匹配过程。
*/
#include <stdio.h>
#include <malloc.h>
#define MAX_SIZE 100
typedef struct
{
char data[MAX_SIZE]; // 串中字符
int length; // 串长
}SqString; // 声明顺序串类型
/*-----------------将字符串常量赋给串s--------------------*/
static void str_assign(SqString &s, char cstr[])
{
int i;
for(i = 0; cstr[i] != '\0'; i++)
s.data[i] = cstr[i];
s.length = i;
}
/*-----------------销毁串--------------------*/
static void destroy_str(SqString &s)
{
}
/*-----------------输出串s--------------------*/
static void disp_str(SqString s)
{
int i;
if(s.length > 0)
{
for(i = 0; i < s.length; i++)
printf("%c", s.data[i]);
printf("\n");
}
}
/*-----------------由模式串t求出next数组值--------------------*/
static void get_next(SqString t, int next[])
{
int j = 0, k = -1;
next[0] = -1;
while(j < t.length - 1)
{
if(k == -1 || t.data[j] == t.data[k]) // k为-1或比较的字符相等时
{
j++;
k++;
next[j] = k;
}
else
k = next[k];
}
}
/*-----------------显示匹配状态信息--------------------*/
static void display(SqString s, SqString t, int i, int j)
{
int k;
printf(" ");
for(k = 0; k < i; k++)
printf(" ");
printf("↓ i = %d, j = %d\n", i, j); // 显示i指向s中的字符
printf("s:");
for(k = 0; k < s.length; k++) // 显示s
printf("%c ", s.data[k]);
printf("\n");
printf("t:");
for(k = 0; k < i - j; k++) // 显示t前面的空格
printf(" ");
for(k = 0; k < t.length; k++) // 显示t
printf("%c ", t.data[k]);
printf("\n");
for(k = 0; k < i - j; k++) // 显示t前面的空格
printf(" ");
for(k = 0; k <= j; k++) // 显示j前面的空格
printf(" ");
printf("↑\n"); // 显示j指向的t中的字符
}
/**
* 利用KMP算法求串t在串s中出现的次数
* 算法思路:
* 用times记录次数,初始时为0。当一次匹配成功后,将times增1,并置j=0继续匹配。
*/
static int count_times(SqString s, SqString t)
{
int i = 0, j = 0;
int times = 0; // 串t在串s中出现的次数
int next[MAX_SIZE];
get_next(t, next);
display(s, t, i, j);
while(i < s.length && j < t.length)
{
if((j == -1) || (s.data[i] == t.data[j]))
{
// i,j各增1
i++;
j++;
}
else
{
// i不变,j后退
j = next[j];
display(s, t, i, j);
}
if(j == t.length)
{
display(s, t, i, j);
printf("\t成功匹配1次\n");
times++;
j = 0; // j设置为0,继续匹配
}
}
return times;
}
int main(int argc, char *argv[])
{
SqString s, t;
str_assign(s, "aaabbdaabbde");
str_assign(t, "aabbd");
printf("t在s中出现的次数:%d\n", count_times(s, t));
destroy_str(s);
destroy_str(t);
return 0;
}
测试结果:
↓ i = 0, j = 0
s:a a a b b d a a b b d e
t:a a b b d
↑
↓ i = 2, j = 1
s:a a a b b d a a b b d e
t: a a b b d
↑
↓ i = 6, j = 5
s:a a a b b d a a b b d e
t: a a b b d
↑
成功匹配1次
↓ i = 11, j = 5
s:a a a b b d a a b b d e
t: a a b b d
↑
成功匹配1次
↓ i = 11, j = -1
s:a a a b b d a a b b d e
t: a a b b d
↑
t在s中出现的次数:2