KMP算法——统计主串中与模式串匹配的个数,输出匹配数量及对应的匹配点位置。

3 篇文章 0 订阅
3 篇文章 0 订阅

自定义一个主串和模式串,并根据KMP算法的匹配结果,统计主串中与模式串匹配的个数,输出匹配数量及对应的匹配点位置。


前言

本代码仅供参考,萌新乱写,请大佬手下留情

一、实验目的

自定义一个主串和模式串,并根据KMP算法的匹配结果,统计主串中与模式串匹配的个数,输出匹配数量及对应的匹配点位置。

例如,主串为  abcabcabcd,子串为 bc,

则程序运行之后结果为:

匹配数量为:3,匹配点位置分别为2,5,8。

 

二、使用步骤

1.代码参考

代码如下:

#include <stdio.h>
#include <string.h>

//定义Next数组(含义:next[i]中元素的前i-1个字符组成的子串中的最长的相同前缀和后缀的长度再加一。)
//char* T为子串用于匹配, int* next为引用的Next数组, length表示子串T的长度
//这个next各个元素的用于记录子串中以i(当前引用到的第i的元素前的前缀与后缀相同的个数<不包含i元素本身>
//即next[1]到next[length + 1] (下标从1开始)
void Next(char* T, int* next, int Length) 
{
    int i = 1;  //i是即子串长度,同时作为子串的指针,从子串第一个字段开始依次后移,也就是指向这个子串中的后缀的最后一个元素;
    next[1] = 0;//第一个元素前无元素,定义next[1]是0
    int j = 0;  //j表示相同的前缀和后缀的长度,即指向子串中的前缀的最后一个元素;
   
    while (i < Length)//下标长度小于子串长度时执行
    {
        //若T[i] == T[j],即表示T子串中长度为i的字符串中——长度为j+1的前缀与长度同为为j+1后缀
        //若不存在,则直接进入下一次循环,比较i+1长度的字符串;
        //next[i] 表示前i-1个字符组成的子串中的相等的前缀和后缀的长度再加一1
        //j = 0即前缀后缀长度都为0,不进行比较,直接移到下一次循环中
        if (j == 0 || T[i - 1] == T[j - 1]) 
        {
            i++;//字符串长度增加
            j++;//无论是否匹配,next的下一个数都+1;
            next[i] = j;
        }
        //若匹配失败
        //重新赋予j匹配失败的前一字段的长度上+1,即表示后缀字符串相同的前缀字符串最后一个字符所在的位置
        //每次匹配失败后,利用j = next[j]可以轻松找到次长前缀字符串的最后一个字符与该字符进行比较。
        else 
        {
            j = next[j];
        }
    }
}

//KMP算法
//S表示匹配主体字符串,T表示匹配子串
//Slen表示匹配主体字符串长度,Tlen同理
int KMP(char* S, char* T, int Slen, int Tlen, int* Size) 
{
    int x = 0; //用作计数器,来记录Size存储与字符串匹配的位置的数组下标
    //定义匹配数组的长度(为了防止堆栈在匹配上溢出,增加匹配数组的长度)
    int* next = new int[Tlen + 10];
    //根据模式串T,初始化next数组
    Next(T, next, Tlen + 10);
    int allindex = 0;
    int i = 1;
    int j = 1;
    while (i <= Slen) //循环条件,判断匹配字段的下标是否超过自身长度
    {
        //S[i-1]==T[j-1],如果对应位置字符相等,两种情况下,指向当前测试的两个指针下标i和j都向后移
        if (j == 0 || S[i - 1] == T[j - 1]) 
        {
            i++;
            j++;
        }
        else 
        {
            j = next[j];//如果测试的两个字符不相等,i不动,j变为当前测试字符串的next值
        }
        // 若j(后缀长度超过自身长度),则表示匹配成功
        //因为当j的长度大于匹配子串的长度时,表示j长度的子串匹配完成后,j还会再加一,所以当子串匹配完成时j的值应该是(Tlen + 1)
        if (j >Tlen)
        {
            allindex++;
            Size[x] = i - Tlen;
            x++;
            j = next[j];

        }
    }
    
    return allindex;
}

//主函数
int main() 
{
    //获取输入的主串
    printf("请输入需要匹配的主串:");
    char A[999];
    gets_s(A);
    int lengthA = strlen(A);//获取字符串长度
    char* a = A;
    printf("\n");
    //获取输入的子串
    printf("请输入需要匹配的子串:");
    char B[999];
    gets_s(B);
    int lengthB = strlen(B);//获取字符串长度
    char* b = B;
    printf("\n");

    int* Size = new int[999];//创建匹配位置数组
    int All_index = KMP(a, b, lengthA, lengthB, Size);//获取匹配总数
    printf("匹配数量为:%d ,匹配点位置分别为:", All_index);
    for (int i = 0; i < All_index; i++)
    {
        printf("%d ",Size[i]);//输出匹配的位置
    }
    return 0;
}

总结

作者:KUST_CZY

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值