前言
本文主要讲述串的三种模式匹配算法(主串和模式串中字符都存放在下标1-length中)。
一、简单模式匹配算法
1.算法思想
(1)定义i和j两个指针,i指向主串,j指向模式串,i=j=1;
(2)i指向主串最后一个元素的下一个位置之前并且j指向模式串最后一个元素的下一个位置之前循环:
a.如果主串str.ch[i]==模式串substr.ch[j]:i往后移一位,j往后 移一位;
b.如果不相等的话,j指向模式串的第一位,i回到i-j+2的位置。
如图所示:
2.简单模式匹配算法代码
代码如下(示例):
//简单匹配算法
int index(Str str, Str substr){
int i = 1;//i指向主串
int j = 1;//j指向模式串
while (i <= str.length&&j <= substr.length){
if (str.ch[i] == substr.ch[j]){
i++;
j++;
}
else{//不相等时
j = 1;
i = i - j + 2;
}
}
if (j > substr.length){//匹配成功
printf("匹配成功!");
return i - substr.length;
}
else{//匹配失败
printf("匹配失败!");
return 0;
}
}
3.测试结果
完整版代码如下(示例):
#include<stdio.h>
#include<stdlib.h>
typedef struct{
char *ch;
int length;
}Str;
//初始化
void Init(Str &str){
str.ch = NULL;
str.length = 0;
}
//赋值
int Strassign(Str &str,char *a){
if (str.ch){
free(str.ch);
str.ch = NULL;
str.length = 0;
}
char *b = a;
int len = 0;
while (*b){
len++;
b++;
}
if (len == 0){
return 1;
}
else{
str.ch = (char *)malloc(sizeof(char)*(len + 1));//包括结束符
if (str.ch == NULL){
return 0;
}
else{
b = a;
for (int i = 0; i <= len; i++){
str.ch[i] = *b;
b++;
}
str.length = len;
return 1;
}
}
}
//简单匹配算法
int index(Str str, Str substr){
int i = 1;//i指向主串
int j = 1;//j指向模式串
while (i <= str.length&&j <= substr.length){
if (str.ch[i] == substr.ch[j]){
i++;
j++;
}
else{//不相等时
j = 1;
i = i - j + 2;
}
}
if (j > substr.length){//匹配成功
printf("匹配成功!");
return i - substr.length;
}
else{//匹配失败
printf("匹配失败!");
return 0;
}
}
//测试
void main(){
Str str, substr;
Init(str);
Init(substr);
Strassign(str, " abcdefg");//为保证元素从下标1开始存放,最前为空格
printf("主串为%s\n",str);
Strassign(substr, " fg");//为保证元素从下标1开始存放,最前为空格
printf("模式串为%s\n", substr);
int location = index(str, substr);
printf("模式串在主串中的位置为%d\n",location);
}
二、KMP算法
1.算法思想
(1)先求next数组:
a.模式串的第一个字符与主串i位置不匹配,应从下一个位置和模式串第一个字符继续比较。next[1]=0;
b.模式串j所指字符前的字符串为F,当F中不存在前后重合的部分时(不可将F自身视为和自身重合),则从主串中发生不匹配的字符与模式串第一个字符开始比较。next[j]=1;
c.模式串j所指字符前的字符串为F,当F中存在前后重合的部分时(不可将F自身视为和自身重合),j重新指向的位置恰好是F串中前后相重合子串的长度+1。
(2)利用next数组实现KMP算法。
如图所示:
2.KMP算法代码
代码如下(示例):
//得到next数组
void GetNext(Str substr,int next[]){
int i = 1;//i指向模式串第一个字符
int j = 0;
next[1] = 0;
while (i < substr.length){
if (j==0||substr.ch[i] == substr.ch[j]){
i++;
j++;
next[i] = j;
}
else{
j = next[j];
}
}
for (int i = 1; i < substr.length; i++){
printf("第%d个字符对应的next数组元素值为%d\n",i, next[i]);
}
}
//KMP算法
int KMP(Str str, Str substr,int next[]){
int i = 1;//i指向主串中的第一个字符
int j = 1;//j指向模式串中第一个字符
while (i <= str.length - 1 && j <= substr.length - 1){
if (j == 0 || str.ch[i] == substr.ch[j]){
i++;
j++;
}
else{
j = next[j];
}
}
if (j >= substr.length){
printf("匹配成功!\n");
return i - substr.length+1;
}
else{
printf("匹配失败!\n");
return 0;
}
}
3.测试结果
完整版代码如下(示例):
#include<stdio.h>
#include<stdlib.h>
typedef struct{
char *ch;
int length;
}Str;
//初始化
void Init(Str &str){
str.ch = NULL;
str.length = 0;
}
//赋值
int Strassign(Str &str,char *a){
if (str.ch){
free(str.ch);
str.ch = NULL;
str.length = 0;
}
char *b = a;
int len = 0;
while (*b){
len++;
b++;
}
if (len == 0){
return 1;
}
else{
str.ch = (char *)malloc(sizeof(char)*(len + 1));//包括结束符
if (str.ch == NULL){
return 0;
}
else{
b = a;
for (int i = 0; i <= len; i++){
str.ch[i] = *b;
b++;
}
str.length = len;
return 1;
}
}
}
//得到next数组
void GetNext(Str substr,int next[]){
int i = 1;//i指向模式串第一个字符
int j = 0;
next[1] = 0;
while (i < substr.length){
if (j==0||substr.ch[i] == substr.ch[j]){
i++;
j++;
next[i] = j;
}
else{
j = next[j];
}
}
for (int i = 1; i < substr.length; i++){
printf("第%d个字符对应的next数组元素值为%d\n",i, next[i]);
}
}
//KMP算法
int KMP(Str str, Str substr,int next[]){
int i = 1;//i指向主串中的第一个字符
int j = 1;//j指向模式串中第一个字符
while (i <= str.length - 1 && j <= substr.length - 1){
if (j == 0 || str.ch[i] == substr.ch[j]){
i++;
j++;
}
else{
j = next[j];
}
}
if (j >= substr.length){
printf("匹配成功!\n");
return i - substr.length+1;
}
else{
printf("匹配失败!\n");
return 0;
}
}
//测试
void main(){
Str str, substr;
Init(str);
Init(substr);
Strassign(str, " abcdefg");//为保证元素从下标1开始存放,最前为空格
Strassign(substr, " de");//为保证元素从下标1开始存放,最前为空格
printf("主串为%s\n",str);
printf("模式串为%s\n", substr);
int *next;
next = NULL;
next = (int *)malloc(sizeof(int)*(substr.length));
GetNext(substr, next);
int location = KMP(str,substr,next);
printf("模式串在主串中的位置为%d\n",location);
}
三、
1.算法思想
(1)先求nextval数组:
a.第一个字符的nextval为0;
b.当下标为j的字符==下标为k(k=next[j])的字符时,nextval[j]=nextval[k];
c.当下标为j的字符!=下标为k(k=next[j])的字符时,nextval[j]=k。
(2)利用nextval数组实现改进的KMP算法。
如图所示:
2.算法代码
代码如下(示例):
//得到nextval数组
void GetNextval(Str substr, int nextval[]){
int i = 1;//i指向模式串第一个字符
int j = 0;
nextval[1] = 0;
while (i < substr.length){
if (j == 0 || substr.ch[i] == substr.ch[j]){
i++;
j++;
if (substr.ch[i] == substr.ch[j])
nextval[i] = nextval[j];
else{
nextval[i] = j;
}
}
else{
j = nextval[j];
}
}
for (int i = 1; i < substr.length; i++){
printf("第%d个字符对应的next数组元素值为%d\n", i, nextval[i]);
}
}
//改进的KMP算法
int KMP(Str str, Str substr, int nextval[]){
int i = 1;//i指向主串中的第一个字符
int j = 1;//j指向模式串中第一个字符
while (i <= str.length - 1 && j <= substr.length - 1){
if (j == 0 || str.ch[i] == substr.ch[j]){
i++;
j++;
}
else{
j = nextval[j];
}
}
if (j >= substr.length){
printf("匹配成功!\n");
return i - substr.length + 1;
}
else{
printf("匹配失败!\n");
return 0;
}
}
3.测试结果
完整版代码如下(示例):
#include<stdio.h>
#include<stdlib.h>
typedef struct{
char *ch;
int length;
}Str;
//初始化
void Init(Str &str){
str.ch = NULL;
str.length = 0;
}
//赋值
int Strassign(Str &str, char *a){
if (str.ch){
free(str.ch);
str.ch = NULL;
str.length = 0;
}
char *b = a;
int len = 0;
while (*b){
len++;
b++;
}
if (len == 0){
return 1;
}
else{
str.ch = (char *)malloc(sizeof(char)*(len + 1));//包括结束符
if (str.ch == NULL){
return 0;
}
else{
b = a;
for (int i = 0; i <= len; i++){
str.ch[i] = *b;
b++;
}
str.length = len;
return 1;
}
}
}
//得到nextval数组
void GetNextval(Str substr, int nextval[]){
int i = 1;//i指向模式串第一个字符
int j = 0;
nextval[1] = 0;
while (i < substr.length){
if (j == 0 || substr.ch[i] == substr.ch[j]){
i++;
j++;
if (substr.ch[i] == substr.ch[j])
nextval[i] = nextval[j];
else{
nextval[i] = j;
}
}
else{
j = nextval[j];
}
}
for (int i = 1; i < substr.length; i++){
printf("第%d个字符对应的next数组元素值为%d\n", i, nextval[i]);
}
}
//改进的KMP算法
int KMP(Str str, Str substr, int nextval[]){
int i = 1;//i指向主串中的第一个字符
int j = 1;//j指向模式串中第一个字符
while (i <= str.length - 1 && j <= substr.length - 1){
if (j == 0 || str.ch[i] == substr.ch[j]){
i++;
j++;
}
else{
j = nextval[j];
}
}
if (j >= substr.length){
printf("匹配成功!\n");
return i - substr.length + 1;
}
else{
printf("匹配失败!\n");
return 0;
}
}
//测试
void main(){
Str str, substr;
Init(str);
Init(substr);
Strassign(str, " abcdefg");//为保证元素从下标1开始存放,最前为空格
Strassign(substr, " fuh");//为保证元素从下标1开始存放,最前为空格
printf("主串为%s\n", str);
printf("模式串为%s\n", substr);
int *nextval;
nextval = NULL;
nextval = (int *)malloc(sizeof(int)*(substr.length));
GetNextval(substr, nextval);
int location = KMP(str, substr, nextval);
printf("模式串在主串中的位置为%d\n", location);
}