2018年数据结构实验之串的匹配
做这样一个大作业其实挺锻炼能力的。一方面是实验中的各种情况要考虑全面,另外就是debug能力…好烦啊
BF算法很简单,其实就是暴力。KMP算法说实话,不太好理解,我当时也是看了很多博客,还去B站看了视频,又自己研究了好久才搞懂的,这里就不解释了…对了还要注意,KMP算法的理解其实分为两个阶段,第一阶段是应付期末考试和考研,即你不需要把代码写出来,只需要手动求解next数组,第二阶段是彻底理解原理,能够将代码敲出来,我觉得大家在学习过程中还是要扎实一些吧,仔细看看博客,把原理搞清楚。
讲明白并不容易,这里给出我当时主要参考的2篇博客吧。
(原创)详解KMP算法
【经典算法】——KMP,深入讲解next数组的求解
再给一个B站的视频。
计算机考研数据结构之KMP算法
然后就不BB了,年代太久远,以后写代码要注意写注释啊!!!!哭唧唧。
#include<stdio.h>
#include<string.h>
#define maxn 100005
///m<n
///剩余长度
char s[100],p[100],ss[maxn],pp[maxn];
int k,next[maxn],nextval[maxn],book[maxn];
int change(char *pp)///处理pp数组,将字符数组转化为int型变量
{
int k=strlen(pp);
int sum=0;
for(int i=0;pp[i]!='\0';i++){
if(pp[i]<='9'&&pp[i]>='0'){
sum=sum*10+pp[i]-'0';
}
else{
printf("请输入数字来表示位置!\n");
return -1;
}
}
return sum;
}
void Init()///初始化各个数组
{
for(int i=0;i<maxn;i++){
book[i]=0;
next[i]=0;
nextval[i]=0;
}
}
void print()///格式化打印操作栏
{
printf("**************************************************\n");
printf("——————-[ 字符串匹配系统功能栏 ]———-------\n");
printf("**************************************************\n");
printf("* 1.输入主串、子串和匹配的起始位置 *\n");
printf("* 2.朴素的模式匹配算法 *\n");
printf("* 3.KMP算法(Next[]) *\n");
printf("* 4.KMP改进算法(NextVal[]) *\n");
printf("* 0.退出管理系统 *\n");
printf("--------------------------------------------------\n");
printf(" 请输入你要选择的功能:\n");
}
void InPut()///输入函数
{
printf("请输入主串:");
scanf("%s",ss);
if(strlen(ss)>100){
printf("主串长度应不大于100,请重新输入!\n");
InPut();
}
printf("请输入子串:");
scanf("%s",pp);
if(strlen(pp)>100){
printf("模式串长度应不大于100,请重新输入!\n");
InPut();
}
int i;
for(i=0;ss[i]!='\0';i++)
s[i]=ss[i];
s[i]='\0';
for(i=0;pp[i]!='\0';i++)
p[i]=pp[i];
p[i]='\0';
int m=strlen(s);
int n=strlen(p);
if(m<n){
printf("主串长度应不小于模式串长度!请重新输入!\n");
InPut();
}
}
void BF()///BF算法函数
{
Init();///初始化BOOK数组,记录各字符匹配次数
char pp[100];
printf("请输入主串匹配的起始位置:");
//scanf("%d",&k);
scanf("%s",pp);
k=change(pp);
if(k==-1){
BF();
return ;
}
int i=k-1,j=0;
int cnt=0;
int m=strlen(s),n=strlen(p);
///判断主串匹配位置是否超出主串范围
if(i+1>m||i==-1){
printf("请从主串内开始匹配!\n");
getchar();
BF();
return;
}
printf("匹配具体过程如下:\n");
while(i<m&&j<n){///判断主串剩余个数,减少比较次数
if(m-j<n){
printf("匹配失败!\n");
break;
}
if(j==0){
printf("%s\n",s);
for(int r=0;r<i;r++)
printf(" ");
}
if(s[i]==p[j]){
book[j]++;///记录匹配次数
i++;
j++;
}
else{
for(int r=0;r<=j;r++)
printf("%c",p[r]);
printf("\n");
cnt++;///记录匹配总趟数
book[j]++;///记录匹配次数
i=i-j+1;
j=0;
}
}
if(m-j<n)
printf("\n");
else if(j==n){
printf("%s\n",p);
printf("匹配成功!\n匹配总趟数为:%d\n匹配成功时的位置序号为:%d\n",cnt+1,i-j+1);
printf("模式各个字符比较次数为:");
for(int i=0;i<n;i++)
printf("%d ",book[i]);
printf("\n");
}
else{
printf("%s\n",p);
printf("匹配失败!\n匹配总趟数为:%d\n",cnt+1);
printf("模式各个字符比较次数为:");
for(int i=0;i<n;i++)
printf("%d ",book[i]);
printf("\n");
}
}
void get_next()
{
Init();
next[0]=-1;
int j=0,k=-1;
int m=strlen(p);
while(j<m){
if(k==-1||p[k]==p[j]){
next[j+1]=k+1;
j++;
k++;
}
else{
k=next[k];
}
}
}
void get_nextval()
{
Init();
nextval[0]=-1;
int j=0,k=-1;
int m=strlen(p);
while(j<m){
if(k==-1||p[k]==p[j]){
if(p[k+1]==p[j+1])
nextval[j+1]=nextval[k+1];
else
nextval[j+1]=k+1;
j++;
k++;
}
else
k=nextval[k];
}
}
void KMP(int c)
{
char pp[100];
printf("请输入主串匹配的起始位置:");///如果输入的不是数字怎么办
scanf("%s",pp);
k=change(pp);
if(k==-1){
BF();
return ;
}
//scanf("%d",&k);
int i=k-1,j=0,cnt=0;
int m=strlen(s),n=strlen(p);
if(i+1>m||i==-1){
printf("请从主串内开始匹配!\n");
getchar();
KMP(c);
return;
}
int sp=1;///定义一个失配标记
while(i<m&&j<n){
if(m-j<n){
printf("匹配失败!\n");
break;
}
if(sp==1){
printf("%s\n",s);
for(int r=0;r<i-j;r++)
printf(" ");
}
if(j==-1||s[i]==p[j]){
sp=0;
book[j]++;///记录比较次数
i++;
j++;
}
else{///失配
for(int r=0;r<=j;r++)
printf("%c",p[r]);
printf("\n");
sp=1;
book[j]++;///记录比较次数
if(c==0) j=next[j];
if(c==1) j=nextval[j];
cnt++;///记录匹配趟数
}
}
if(m-j<n){
printf("\n");
}
else if(j==n){
printf("%s\n",p);
printf("匹配成功!\n匹配总趟数为:%d\n匹配成功时的位置序号为:%d\n",cnt+1,i-j+1);
printf("模式串各字符比较次数为:");
for(int i=0;i<n;i++)
printf("%d ",book[i]);
printf("\n");
printf("next/nextval数组如下所示:\n");
for(int r=0;r<n;r++)
if(c==0)
printf("%d ",next[r]);
else if(c==1)
printf("%d ",nextval[r]);
printf("\n");
}
else{
printf("%s\n",p);
printf("匹配失败!\n匹配总趟数为:%d\n",cnt+1);
printf("模式串各字符比较次数为:");
for(int i=0;i<n;i++)
printf("%d ",book[i]);
printf("\n");
printf("next/nextval数组如下所示:\n");
for(int r=0;r<n;r++)
if(c==0)
printf("%d ",next[r]);
else if(c==1)
printf("%d ",nextval[r]);
printf("\n");
}
}
///bacbababadababacamba
///ababaca
/*string source = "ABCDABCEAAAABASABCDABCADABCDABCEAABCDABCEAAABASABCDABCAABLAKABCDABABCDABCEAAADSFDABCADABCDABCEAAABCDABCEAAABASABCDABCADABCDABCEAAABLAKABLAKK";
// string pattern = "abcaaabcab";
string pattern = "ABCDABCEAAABASABCDABCADABCDABCEAAABLAK";*/
int main()
{
int o=0;
while(1){
//judge=0;
char t[100];
print();
scanf("%s",t);
if(o!=0)
getchar();
o++;
if(strlen(t)!=1||t[0]<'0'||t[0]>'4'){
printf("输入错误,请输入0-4中的数字\n");
continue;
}
if(t[0]=='1'){
InPut();
}
else if(t[0]=='2'&&strlen(s)!=0&&strlen(p)!=0){
BF();
}
else if(t[0]=='3'&&strlen(s)!=0&&strlen(p)!=0){
get_next();
KMP(0);
}
else if(t[0]=='4'&&strlen(s)!=0&&strlen(p)!=0){
get_nextval();
KMP(1);
}
else if(t[0]=='0'){
printf("系统退出,欢迎再次使用该系统!\n");
break;
}
else if(strlen(s)==0||strlen(p)==0){
printf("请先输入主串和模式串之后再进行匹配!\n");
}
else{
printf("输入错误,请输入0-4中的数字\n");
continue;
}
}
return 0;
}