串的模式匹配(朴素算法和KMP算法以及KMP的改进算法)

在学习算法之前我们先认识一些术语

子串:串中任意个连续的字符组成的子序列.

主串:包含子串的串

模式串:在主串中要查找的子串

串的模式匹配一般有两种算法即朴素算法和KMP算法,下面我们来一一介绍

一、朴素算法(暴力算法)

        算法思想

               1. 将主串中所有长度为m的子串与模式串对比

                2.主串长度n,模式串长度m

                3.找到第一个与模式串匹配的子串,并返回子串起始位置

                4.若所有子串都不匹配,则返回0

        因为朴素算法通过一个一个比较来找到主串中包含的模式串,所以时间复杂度为O(nm)

代码实现:

#include <stdio.h>
#include<string.h>
int main()
{
    char S[] = "aaaab";//主串
    char Q[] = "aac";//模式串
    int Slen = (int)strlen(S);
    int Qlen = (int)strlen(Q);
    int i, j;
    i = j = 0;
    while (i < Slen && j < Qlen)
    {
        if (S[i] != Q[j])
        {
            i = i - j + 1;
            j = 0;
        }
        else
        {
            i++;
            j++;
        }
    }
    if (j == Qlen)
        printf("找到了\n");
    else
        printf("没找到\n");
    return 0;
}

二、KMP算法

算法思想
        1.主串长度n,模式串长度m
        2.利用两个指针i和j,i指向主串,j指向模式串
        3.如果发现i不等于j的话,i不动,j指向next数组的下标
        4.若所有子串都不匹配,则返回0
求next数组的方法
        1.Next[1]可以直接写0
        2.Next[2]可以直接写1
        3.其他的next在不匹配的位置前,划一条分界线,模式串一步一步往后退,知道分界线之        前 “能对上”,或模式串完全跨过分界线为止。
        此时j指向哪里,next数值就是多少

代码实现:

#include<stdio.h>
#include<string.h>
#define MainLen 7
#define ModelLen 4
int main()
{
    char arr[] = "abaabab";//定义主串
    char S[] = "aaba";//模式串
    int next[ModelLen] = {-1,0,1,0};//next数组,根据上面的方法手动模拟
    int i = 0;
    int j = 0;

    while (i < MainLen && j < ModelLen)
    {
        if (j == -1 || arr[i] == S[j])
        {
            i++;
            j++;
        }
        else
        {
            j = next[j];
        }
    }
    if (j == ModelLen)
        printf("找到了\n");
    else
        printf("没找到\n");

    return 0;
}

KMP算法的时间复杂度为O(n+m)相比于朴素算法提高了很多

三、KMP算法的优化

        KMP的优化算法主要是优化了next数组的逻辑
        如果当前匹配失败的这个元素,与next[j]指向的下一个元素一样的话
        那么下一个数也一定会失败,所以我们可以减少不必要的比较
        如果当前失败的元素与下一个要比较的元素的一样的话,我们可以直接令当前失败的元素直接指向下一次要比较的元素下标

#include<stdio.h>
#include<string.h>
#define MainLen 7
#define ModelLen 4
int main()
{
    char arr[] = "abaabab";//定义主串
    char S[] = "aaba";//模式串
    int next[ModelLen] = { -1,0,1,0 };//next数组,根据上面的方法手动模拟

    //注:408考试中只要求会手写  我把手写和代码都写出来可供参考
    //int nextval[ModelLen] = {-1,-1,1,-1}; //优化数组  
    int nextval[ModelLen] = {0};
    //下面是代码的实现(408不要求)
    nextval[0] = -1;//第一个数固定为-1
    int x = 1;
    for (x; x < ModelLen; x++)
    {
        if (S[x] == S[next[x]])//如果当前的数与下一个数相等的话
            nextval[x] = nextval[next[x]];//直接令当前的元素下标等于下一个元素指向的下标
        else
            nextval[x] = next[x];//如果不相等直接赋值
    }
    int i = 0;
    int j = 0;

    while (i < MainLen && j < ModelLen)
    {
        if (j == -1 || arr[i] == S[j])
        {
            i++;
            j++;
        }
        else
        {
            j = nextval[j];
        }
    }
    if (j == ModelLen)
        printf("找到了\n");
    else
        printf("没找到\n");

    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值