Bootstrap

数据结构——基于字符串模式匹配算法的病毒感染检测

实验四 基于字符串模式匹配算法的病毒感染检测

【实验目的】
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   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;
	}
}


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相同的序列 
		else
		printf("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   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);       // 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相同的序列 
		else
		printf("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相同的序列 
		else
		printf("NO\n");//即在人体dna中找到与病毒dna相同的序列 
	}	
	
			


	
		
		
	
	
	
		
	 
	 return 0;
		
}

在这里插入图片描述

;