基于字符串模式匹配算法的病毒感染检测问题

目录

1 需求分析

1.1 任务

1.2 输入、输出形式

1.3 程序功能

2 概要设计

2.1 抽象数据类型定义

2.2 主程序流程图

3 详细设计

3.1 存储空间初始化

3.2 模式匹配

3.3 循环修改子串

4 调试分析

4.1 调试过程存在的问题

4.2 时空复杂度

4.3 经验体会

5 数据测试与结果

5.1 主串中直接包含子串(abc **abc**型)

5.2 主串中包含子串的变形(abc  **cba**型)

5.3 主串不包含子串及其变形

5.4 随机输入实验

5.5 退出程序


1 需求分析

1.1 任务

        某些病毒DNA为环形序列,现研究人员已收集了大量病毒DNA序列和人的DNA序列数据,并将DNA表示成由一些字母组成的字符串序列,然后检测某种病毒DNA序列是否在人DNA中出现,若出现,则该患者已感染该病毒,否则没有感染。即该程序将用于检测子串(病毒序列)是否在主串(患者DNA)中出现。特别注意,人的DNA序列为线性,但病毒序列为环形。

1.2 输入、输出形式

        输入形式:多组数据,每组数据有1行,为序列A和B,A对应病毒的DNA序列,B对应人的DNA序列。当A、B均为“0”时输入结束,退出程序执行。

        输出形式:对于每组数据输出1行,若患者感染了病毒输出“YES”,否则输出“NO”。特殊的,当程序退出时提示程序退出。

        具体示例如下图

1.3 程序功能

        (1)基于顺序存储结构的字符串初始化:为定义的字符串分配字符存储空间,并初始化其内部其他数值。

        (2)模式匹配:对两字符串进行比较,判断主串中是否包含子串。若包含,则返回‘Y’,否则返回‘N’。、

        (3)循环改变子串:子串为循环系列,因此当一轮比较完成之后需要对子串进行修改,修改方式则是将字符串最后一个字符放到字符串第一个位置。

2 概要设计

2.1 抽象数据类型定义

typedef struct S{

    char *str; //存放字符串

    int length; //当前字符数量

    int size; //当前存储空间大小

    /* str采用顺序结构存储字符串,length保存字符串长度,size保存当前str空间的总大小*/

}String;

2.2 主程序流程图

3 详细设计

3.1 存储空间初始化

Status InitString(String *S){ //初始化字符串存储空间
    (*S).str=(char*)malloc(Init_String*sizeof(char));
    if(!(*S).str) exit(OVERFLOW);
    (*S).length=0;
    (*S).size=Init_String;
    return OK;
}

3.2 模式匹配

char Modlecmp(String son,String main){ //模式匹配
    int flag,i,j;
    flag=0;
    for(i=0,j=0;i<main.length+1; ){
        if(j==son.length){
            //当子串指针等于子串长度时,即匹配成功;则flag置1,退出循环;
            flag=1;break;
        }
        if(son.str[j]==main.str[i]){
            //当子串与主串指针当前所指位置字符一致,两个指针后移,并跳过后续代码
            i++;j++;continue;
        }
        if(son.str[j]!=main.str[i]){
            //当子串与主串指针当前所指位置字符不一致,子串指针置0
            j=0;
            if(son.str[j]!=main.str[i])  i++;    //当子串与主串指针当前所指位置字符再次不一致,主串指针后移
        }
    }
    if(flag==1) return 'Y';
    return 'N';
}

3.3 循环修改子串

Status Change(String *s){
    int i;
    if(s->length>=s->size){ //判断存储空间是否足够
        s->str=(char *)realloc(s->str,(Init_String+StringIncrease)*sizeof(char));
        if(!s->str) exit(OVERFLOW);
        s->size+=StringIncrease;
    }
    for(i=s->length-1;i>=0;i--){ //从后依次将字符后移一位
        s->str[i+1]=s->str[i];
    }
    s->str[0]=s->str[s->length]; //将最后一位字符放置到第一位
    s->str[s->length]='\0'; //原先最后一位字符位置置'\0'
    return OK;
}

4 调试分析

4.1 调试过程存在的问题

        (1)问题1:调用模式匹配无法正常返回,即“result=Modlecmp(str_son,str_main);”语句无法正常返回并赋值。

        分析:模式匹配模块代码设计错误,推测使其中的循环进入死循环导致无法终止。

        解决:重写模式匹配模块代码。

       (2)问题2:比较不完全。在调用模式匹配函数的时候,当输入为类似于“abahjakdjaba”(即子串出现在主串末尾)时,函数返回值总是为‘N’;

        分析:子串与主串没有完全匹配完成就退出循环:

        解决:增加循环次数,将“i<main.length”改为“i<main.length+1”,使得子串与主串充分匹配。

4.2 时空复杂度

4.3 经验体会

        (1)gets和scanf的异同:gets和scanf都可以用于字符串的输入;但gets为字符串输入的一种专用函数,可以读入一切字符,并以“回车”符为输入终止符。因此gets函数可以读入空格将一行形成一个字符串。但是scanf为标准格式化输入函数,以空格、tab、回车等为输入终止符,不会将输入的一行组成一个字符串,而是会依据空格切分。

        (2)算法思想与代码转换:一个算法思想设计完成之后,在转换成代码的时候要多考虑细节问题,不能与思想一样过于宽泛。如果代码过于宽泛容易造成运行结果错误或者无法运行的情况。可以首先在草稿纸上写出简易代码并手动执行一次,再用软件编写代码,降低出错的可能性。

        (3)单步分析:当代码执行出错时,可以使用单步跟踪的分析方法来对代码进行分析。可以使用“printf”将代码关键变量的值输出到屏幕,来分析关键变量值是否正确,以此来判断代码执行情况。对于函数调用方面,可以在函数中加入“printf”来作为函数是否调用的标记。

5 数据测试与结果

5.1 主串中直接包含子串(abc **abc**型)

5.2 主串中包含子串的变形(abc  **cba**型)

5.3 主串不包含子串及其变形

5.4 随机输入实验

5.5 退出程序

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SouthDreamYaoJia

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值