实验四 基于字符串模式匹配算法的病毒感染检测
【实验目的】
1.掌握字符串的顺序存储表示方法。
2.掌握字符串模式匹配BF算法和KMP算法的实现。
【实验内容】
问题描述
医学研究者最近发现了某些新病毒,通过对这些病毒的分析,得知它们的DNA序列都是环状的。现在研究者已收集了大量的病毒DNA和人的DNA数据,想快速检测出这些人是否感染了相应的病毒。为了方便研究,研究者将人的DNA和病毒DNA均表示成由一些字母组成的字符序列,然后检测某种病毒DNA序列是否在患者的DNA序列中出现过。如果出现过,则此人感染了该病毒,否则没有感染。例如,假设病毒的DNA序列为baa,患者1的DNA序列为aaabbba,则感染;患者2的DNA序列为babbba,则未感染。(注意,人的DNA序列是线性的,而病毒的DNA序列是环状的。)
输入要求
多组数据,每组数据有1行,为序列A和B,A对应病毒的DNA序列,B对应人的DNA序列。A和B都为“0”时输入结束。
输入样例
abbab abbabaab
baa cacdvcabacsd
abc def
0 0
输出样例
YES
YES
NO
【实验提示】
此实验内容即要求实现教材算法的具体案例。利用BF算法来实现字符串的模式匹配过程的,效率较低,。利用KMP算法完成模式匹配以提高算法的效率。
解决方法1:暴力算法
#include <stdio.h> // printf(); scanf()
#include <stdlib.h> // exit()
#include <malloc.h> // malloc()
#include <time.h> // srand((unsigned)time(NULL));
#include <string.h>#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0typedef int Status;typedef int ElemType;#define MAXSTRLEN 255
typedef unsigned char SString[MAXSTRLEN + 1]; Status StrAssign(SString &T, char *chars) {if(strlen(chars) > MAXSTRLEN)return ERROR;else {T[0] = strlen(chars); for(int i=1; i<=T[0]; i++)T[i] = *(chars+i-1);return OK;}
}Status StrCopy(SString &T, SString S) {for(int i=0; i<=S[0]; i++)T[i] = S[i];return OK;
}int StrLength(SString S) {return S[0];
}int index(SString S,SString T,int pos)
{int i=pos,j=1;while(i<=S[0]&&j<=T[0]){if(S[i]==T[j]){++i;++j;}else {i=i-j+2;j=1;}}if(j>T[0])return i-T[0];else return 0;} int main()
{ int flag[100];int w=0; int x;int number;int pos;char c[MAXSTRLEN+1],d[MAXSTRLEN+1];SString S;SString T;SString Z;do{scanf("%s",c);scanf("%s",d);StrAssign(S, c);StrAssign(T, d);char str[T[0]];for(int i=0; i<=S[0]; i++)str[i] = T[i+1];int i=0;Z[0]=T[0];for(i=0;i<T[0];i++){for(int j=1;j<=T[0];j++){Z[j]=str[(j+i)%(T[0])]; }number=index(S,Z,pos);if(number!=0&&strcmp(c,"0")!=0&&strcmp(d,"0")!=0){flag[w++]=1;break; } }if(i==T[0]&&strcmp(c,"0")!=0&&strcmp(d,"0")!=0)flag[w++]=0;}while(strcmp(c,"0")!=0&&strcmp(d,"0")!=0);for(int e=0;e<w;e++){if(flag[e]==1)printf("YES\n");//即在人体dna中找到与病毒dna相同的序列 elseprintf("NO\n");//即在人体dna中找到与病毒dna相同的序列 } return 0;}
解决方法2:kmp算法
#include <stdio.h> // printf(); scanf()
#include <stdlib.h> // exit()
#include <malloc.h> // malloc()
#include <time.h> // srand((unsigned)time(NULL));
#include <string.h>#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0typedef int Status;
typedef int ElemType;
#define MAXSTRLEN 255
typedef unsigned char SString[MAXSTRLEN + 1];Status StrAssign(SString &T, char *chars) {if(strlen(chars) > MAXSTRLEN)return ERROR;else {T[0] = strlen(chars); // 0号单元存放串的长度for(int i=1; i<=T[0]; i++)T[i] = *(chars+i-1);return OK;}
}Status StrCopy(SString &T, SString S) {for(int i=0; i<=S[0]; i++)T[i] = S[i];return OK;
}int StrLength(SString S) {return S[0];
}void get_next(SString T,int next[])
{int j; int i=1;next[1]=0;j=0;while(i<T[0]){if(j==0||T[i]==T[j]){i++;j++;next[i]=j;}else j=next[j];}
}int Index_KMP(SString S,SString T,int pos)
{ int next[MAXSTRLEN+1]; get_next(T,next);int i=pos; int j=1;while(i<=S[0]&&j<=T[0])//i j都不超过其串的长度{//失配 //1:失配,当j==0时,则目标主串的检测指针前进一位,模式串检测指针回到T[1].进行下一趟的比较//2:失配,当j>0时,那么在下一趟比较时,模式串的起始位置为Tnext[j],目标主串S的检测指针不回溯,仍然指向上一趟失配的位置 if(j==0||S[i]==T[j]){++i;++j;//继续比较后继字符 }else j=next[j];//模式串向右移动 }if(j>T[0]) return i-T[0];//匹配成功 else return 0;
}int main()
{ int flag[100];int w=0; int x;int number;int pos;char c[MAXSTRLEN+1],d[MAXSTRLEN+1];SString S;SString T;SString Z;do{scanf("%s",d); scanf("%s",c);StrAssign(S, c);StrAssign(T, d);char str[T[0]];for(int i=0; i<=S[0]; i++)str[i] = T[i+1];int i=0;Z[0]=T[0];for(i=0;i<T[0];i++){for(int j=1;j<=T[0];j++){Z[j]=str[(j+i)%(T[0])]; }//StrPrint(Z); //printf("\n");number=Index_KMP(S,Z,pos);if(number!=0&&strcmp(c,"0")!=0&&strcmp(d,"0")!=0){flag[w++]=1;break; } }if(i==T[0]&&strcmp(c,"0")!=0&&strcmp(d,"0")!=0)flag[w++]=0;}while(strcmp(c,"0")!=0&&strcmp(d,"0")!=0);for(int e=0;e<w;e++){if(flag[e]==1)printf("YES\n");//即在人体dna中找到与病毒dna相同的序列 elseprintf("NO\n");//即在人体dna中找到与病毒dna相同的序列 } return 0;}
解决方法3:kmp算法改进版```c
#include <stdio.h> // printf(); scanf()
#include <stdlib.h> // exit()
#include <malloc.h> // malloc()
#include <time.h> // srand((unsigned)time(NULL));
#include <string.h>#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
#define MAXSTRLEN 255
typedef unsigned char SString[MAXSTRLEN + 1]; Status StrAssign(SString &T, char *chars) {if(strlen(chars) > MAXSTRLEN)return ERROR;else {T[0] = strlen(chars); for(int i=1; i<=T[0]; i++)T[i] = *(chars+i-1);return OK;}
}int StrLength(SString S) {return S[0];
}void get_nextval(SString T,int nextval[])
{int j; int i=1;nextval[1]=0;j=0;while(i<T[0]){if(j==0||T[i]==T[j]){i++;j++;if(T[i]!=T[j])nextval[i]=j;else nextval[i]=nextval[j];}else j=nextval[j];}
}int Index_KMP_val(SString S,SString T,int pos)
{ int nextval[MAXSTRLEN+1]; get_nextval(T,nextval);int i=pos; int j=1;while(i<=S[0]&&j<=T[0])//i j都不超过其串的长度{//失配 //1:失配,当j==0时,则目标主串的检测指针前进一位,模式串检测指针回到T[1].进行下一趟的比较//2:失配,当j>0时,那么在下一趟比较时,模式串的起始位置为Tnext[j],目标主串S的检测指针不回溯,仍然指向上一趟失配的位置 if(j==0||S[i]==T[j]){++i;++j;//继续比较后继字符 }else j=nextval[j];//模式串向右移动 }if(j>T[0]) return i-T[0];//匹配成功 else return 0;
}int main()
{ int flag[100];//用于计算循环数组 每次的结果 int w=0; //用于统计flag数组 int x;int number;int pos;char c[MAXSTRLEN+1],d[MAXSTRLEN+1];SString S;SString T;SString Z;do{scanf("%s",d); scanf("%s",c);StrAssign(S, c);StrAssign(T, d);char str[T[0]];for(int i=0; i<=S[0]; i++)str[i] = T[i+1];int i=0;Z[0]=T[0];for(i=0;i<T[0];i++){for(int j=1;j<=T[0];j++){Z[j]=str[(j+i)%(T[0])]; }number=Index_KMP_val(S,Z,pos);if(number!=0&&strcmp(c,"0")!=0&&strcmp(d,"0")!=0){flag[w++]=1;break; } }if(i==T[0]&&strcmp(c,"0")!=0&&strcmp(d,"0")!=0)flag[w++]=0;}while(strcmp(c,"0")!=0&&strcmp(d,"0")!=0);for(int e=0;e<w;e++){if(flag[e]==1)printf("YES\n");//即在人体dna中找到与病毒dna相同的序列 elseprintf("NO\n");//即在人体dna中找到与病毒dna相同的序列 } return 0;}