段文章关键字替换(KMP)

#include<stdio.h>
#include<string.h>
#define MAXN 1000
int next[MAXN];///字串的next
char ans[MAXN];///最终修改的结果
int cnt=0;///全局变量是记录替换的次数
int length(char *s)///求字符串的长度函数
{
    int i,len=0;
    for(i=0;s[i]!='\0';i++)
        len++;
    return len;
}
void getnext(char *s)
{
    int j=-1;
    int i=0;
    next[0]=-1;///一开始字串的第一个位置肯定是没有共同的缀,初始化为-1
    int len=length(s);///求出子串的长度
    while(i<len)///优化版的求next的值
    {
        if(j==-1||s[i]==s[j])///j=-1,让它如果遇到不相同的进入的条件,
        {
            ++i;++j;///相同的话就同时进一位,j其实就是前缀和后缀的共同部分,共同部分的长度
            if(s[i]!=s[j])
                next[i]=j;///如果进入的条件是-1,而不是相等进入,那么就进入这里,也就告诉next没有共同部分,++j就是0
            else
                next[i]=next[j];///既然是相同的就继续找相同的共同缀
        }
        else
            j=next[j];///不相同的话,就从前缀后缀相同的部分接下来的位置继续走
    }
}
int kmp(char *s,char *s1,char *s2)
{
    int i=0,j=0,x=0;
    int k,q;
    int s_len=length(s);///主串的长度
    int s1_len=length(s1);///关键字的子串
    int s2_len=length(s2);///替换的子串
    getnext(s1);///找关键字的next的值
    ans[x++]=s[0];///所以答案的字符都赋值到ans这个数组
    while(i<s_len)///这个循环必须把主串都遍历一遍
    {
        if(j==-1||s[i]==s1[j])
        {
            ++i;++j;///遇到相同的继续走
            ans[x++]=s[i];///并把相应的字符赋值到ans里,并且在这里有没有发现ans的第一个字符是从第二个字符开始存的
            ///因为i自增之后就是下一位了,所以我在开始的时候就把第一个位置存在ans里了
        }
        else
            j=next[j];///不同的时候从前面有前缀和后缀相等的部分的接下来的位置继续走


        if(j==s1_len)///匹配到跟关键字的长度一样说明是匹配的,就进行替换
        {
            --i;///这个很关键,因为如果子串达到子串的长度不是因为下一个不匹配而达到目的,
        ///而是刚刚好的话,那主串自减1,后退一位,接下来这个该匹配的就变成不匹配了,也就是跳过了这个匹配
        ///进行寻找下一个匹配,重复这样的操作。
            ++cnt;///记录替换的次数
            for(q=0,k=x-s1_len-1;q<s2_len;q++,k++)
                {
                    ans[k]=s2[q];///从x-s1_len-1开始匹配,是因为匹配了回到匹配之前的位置开始替换
                }
            x=k;///并把k的位置是赋值到x,因为k是ans最新的位置,那样就达到替换之后的衔接
        }
    }
}
int main()
{
    char s[MAXN],s1[MAXN],s2[MAXN];
    printf("请输入一段英文:\n");
    gets(s);
    printf("请输入关键字:");
    scanf("%s",s1);
    printf("请输入要替换的关键字:");
    scanf("%s",s2);
    kmp(s,s1,s2);
    printf("一共完成 %d 处替换\n",cnt);
    printf("替换之后的文章为:\n");
    puts(ans);
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值