KMPアルゴリズムとウイルス感染検出に適用されるその改良されたアルゴリズムの詳細な説明(Cプログラムの実装)

//文字列KMPアルゴリズムのパターンマッチングプロセスが図に示されているため、説明しません




。//このプログラムは移植性プログラムです。

// Linux / Mac os / Windowsでコンパイルして実行できます。

//欠点がある場合は、それを上げてください。ブロガーは最善を尽くして修正します。

//それがあなたにとって有用であるならば、それを好きにするか、他の人と共有してください。

//盗用および許可なく転載することは固く禁じられています。

//ソースコードはこちらです。刺激を受けたいと思います。

//KMP.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 20

char *s_gets(char *st, int n);
int kmp(const char *s, const char *t, int pos);
void get_next(const char *t, int *next);

int main(int argc, char *argv[])
{
    
    
    int n;
    char str1[LEN];
    char str2[LEN];

    printf("本程序采用KMP模式匹配算法判断子串是否处于主串中\n");
    printf("请输入主串(换行结束输入):\n");
    while (s_gets(str1, LEN) && *str1 != '\0')
    {
    
    
        printf("请输入子串:\n");
        if (s_gets(str2, LEN) && *str2 != '\0')
        {
    
    
            n = kmp(str1, str2, 0); //从起始字符开始匹配,可任意决定匹配位置;
            if (n != -1)
            {
    
    
                printf("子串%s在主串%s中, 子串出现于主串第%d个位置\n", str2, str1, n);
            }
            else
            {
    
    
                printf("子串%s不在主串%s中\n", str2, str1);
            }
            printf("您可以再次输入2串字符串(或换行退出):\n");
        }
    }
    printf("本程序完成!\n");

    return 0;
}

char *s_gets(char *st, int n)
{
    
    
    char *ret_val;
    char *find;

    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
    
    
        find = strchr(st, '\n');
        if (find)
        {
    
    
            *find = '\0';
        }
        else
        {
    
    
            while (getchar() != '\n')
                continue;
        }
    }
    return ret_val;
}

int kmp(const char *s, const char *t, int pos)
{
    
    
    int i = pos;
    int j = 0;
    int slength = strlen(s);                          //获取主串长度;
    int tlength = strlen(t);                          //获取字串长度;
    int *next = (int *)malloc(sizeof(int) * tlength); //构造一个与模式串长度相等的next数组;
    if (NULL == next)
    {
    
    
        fprintf(stderr, "动态内存分配失败!本程序退出!\n");
        exit(EXIT_FAILURE);
    }
    get_next(t, next); //给next数组赋初值;
    while (i < slength && j < tlength)
    {
    
    
        if (j == -1 || s[i] == t[j])
        {
    
    
            i++;
            j++;
        }
        else
        {
    
    
            j = next[j]; //模式串向右滑动;
        }
    }
    free(next); //KMP算法匹配完之后释放next数组的动态内存空间;
    if (j >= tlength)
    {
    
    
        return i - tlength + 1;
    }
    else
    {
    
    
        return -1;
    }
}

void get_next(const char *t, int *next)
{
    
    
    int i = 0;
    int j = -1;
    int len = strlen(t);

    next[0] = -1;
    while (i < len - 1)
    {
    
    
        if (j == -1 || t[i] == t[j])
        {
    
    
            next[++i] = ++j; //next数组中的核心部分,讲解如图所示;
        }
        else
        {
    
    
            j = next[j]; //模式串中的字符部分匹配,再求出next数组的函数值;
        }
    }
    return;
}




//improvement_kmp.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 20

char *s_gets(char *st, int n);
int kmp(const char *s, const char *t, int pos);
void get_nextval(const char *t, int *nextval);

int main(int argc, char *argv[])
{
    
    
    int n;
    char str1[LEN];
    char str2[LEN];

    printf("本程序采用KMP模式匹配算法判断子串是否处于主串中\n");
    printf("请输入主串(换行结束输入):\n");
    while (s_gets(str1, LEN) && *str1 != '\0')
    {
    
    
        printf("请输入子串:\n");
        if (s_gets(str2, LEN) && *str2 != '\0')
        {
    
    
            n = kmp(str1, str2, 0); //从起始字符开始匹配,可任意决定匹配位置;
            if (n != -1)
            {
    
    
                printf("子串%s在主串%s中, 子串出现于主串第%d个位置\n", str2, str1, n);
            }
            else
            {
    
    
                printf("子串%s不在主串%s中\n", str2, str1);
            }
            printf("您可以再次输入2串字符串(或换行退出):\n");
        }
    }
    printf("本程序完成!\n");

    return 0;
}

char *s_gets(char *st, int n)
{
    
    
    char *ret_val;
    char *find;

    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
    
    
        find = strchr(st, '\n');
        if (find)
        {
    
    
            *find = '\0';
        }
        else
        {
    
    
            while (getchar() != '\n')
                continue;
        }
    }
    return ret_val;
}

int kmp(const char *s, const char *t, int pos)
{
    
    
    int i = pos;
    int j = 0;
    int slength = strlen(s);                             //获取主串长度;
    int tlength = strlen(t);                             //获取字串长度;
    int *nextval = (int *)malloc(sizeof(int) * tlength); //构造一个与模式串长度相等的nextval数组;
    if (NULL == nextval)
    {
    
    
        fprintf(stderr, "动态内存分配失败!本程序退出!\n");
        exit(EXIT_FAILURE);
    }
    get_nextval(t, nextval); //给nextval数组赋初值;
    while (i < slength && j < tlength)
    {
    
    
        if (j == -1 || s[i] == t[j])
        {
    
    
            i++;
            j++;
        }
        else
        {
    
    
            j = nextval[j]; //模式串向右滑动;
        }
    }
    free(nextval); //KMP算法匹配完之后释放nextval数组的动态内存空间;
    if (j >= tlength)
    {
    
    
        return i - tlength + 1;
    }
    else
    {
    
    
        return -1;
    }
}

void get_nextval(const char *t, int *nextval)
{
    
    
    int i = 0;
    int j = -1;
    int len = strlen(t);

    nextval[0] = -1;
    while (i < len - 1)
    {
    
    
        if (j == -1 || t[i] == t[j]) //nextval数组中的核心部分,讲解如图所示;
        {
    
    
            ++i, ++j;
            if (t[i] != t[j])
            {
    
    
                nextval[i] = j; //字符不相等时的情况;
            }
            else
            {
    
    
                nextval[i] = nextval[j]; //字符相等时的情况;
            }
        }
        else
        {
    
    
            j = nextval[j]; //模式串中的字符部分匹配,再求出nextval数组的函数值;
        }
    }
    return;
}

// ------------------------------------------------ ---------;

//virus_detection.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define N 4

bool kmp(const char *s, const char *t, int pos);
void get_nextval(const char *t, int *nextval);
void virus_detection(void);

int main(void)
{
    
    
    printf("本程序使用KMP算法查看病毒感染情况(病毒DNA为环状DNA)\n");
    virus_detection();

    return 0;
}

bool kmp(const char *s, const char *t, int pos)
{
    
    
    int i = pos;
    int j = 0;
    int slength = strlen(s);                             //获取主串长度;
    int tlength = strlen(t);                             //获取字串长度;
    int *nextval = (int *)malloc(sizeof(int) * tlength); //构造一个与模式串长度相等的nextval数组;
    if (NULL == nextval)
    {
    
    
        fprintf(stderr, "动态内存分配失败!本程序退出!\n");
        exit(EXIT_FAILURE);
    }
    get_nextval(t, nextval); //给nextval数组赋初值;
    while (i < slength && j < tlength)
    {
    
    
        if (j == -1 || s[i] == t[j])
        {
    
    
            i++;
            j++;
        }
        else
        {
    
    
            j = nextval[j]; //模式串向右滑动;
        }
    }
    free(nextval); //KMP算法匹配完之后释放nextval数组的动态内存空间;
    if (j == tlength)
    {
    
    
        return true;
    }
    else
    {
    
    
        return false;
    }
}

void get_nextval(const char *t, int *nextval)
{
    
    
    int i = 0;
    int j = -1;
    int len = strlen(t);

    nextval[0] = -1;
    while (i < len - 1)
    {
    
    
        if (j == -1 || t[i] == t[j])
        {
    
    
            ++i, ++j;
            if (t[i] != t[j])
            {
    
    
                nextval[i] = j;
            }
            else
            {
    
    
                nextval[i] = nextval[j];
            }
        }
        else
        {
    
    
            j = nextval[j];
        }
    }
    return;
}

void virus_detection(void)
{
    
    
    int i;
    bool flag;
    const char *people[N] = {
    
    "da", "fg", "xi", "baa"};
    const char *virus[N] = {
    
    "abcdabcd", "efef", "hihi", "aaabaaab"};
    //↑病毒DNA为环状DNA故字符串要成环, 原字符串连续存储2次即可;

    for (i = 0; i < N; i++)
    {
    
    
        printf("第%d个人的DNA序列是:%s\n", i + 1, people[i]);
        printf("第%d个病毒的DNA序列是:%s\n", i + 1, virus[i]);
        flag = kmp(virus[i], people[i], 0);
        if (flag)
        {
    
    
            printf("第%d个人感染了病毒\n\n", i + 1);
        }
        else
        {
    
    
            printf("第%d个人未感染病毒\n\n", i + 1);
        }
    }
    return;
}

// ------------------------------------------------ ---------;

// ------------------------------------------------ -2020年6月26日---------------------------------------------- ----------;

おすすめ

転載: blog.csdn.net/m0_46181359/article/details/106974947