字符串匹配及kmp改进算法

            

          字符串最重要的也是最难的就是模式匹配,其他的也是比较简单的东西就不写了而且在最基本上的模式匹配的基础上提出了很多具有改进的算法,各种改进的算法的思想和出发点会在注释中解释

          

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

//int返回第一个匹配起点,a为模式串,b为目标串
//先用一般的算法
int match(char *a,char *b)
{
    int len1 =strlen(a);
    int len2 =strlen(b);
    int i=0,j=0;
    int start=0;
    while(i<len1&&j<len2)
    {
        if(a[i]==b[j])
            i++,j++;
        else
        {
            start++;
            i=0;
            j=start;
        }
        if(i==len1)     //匹配成功
            return j-len1;  //返回
        if((len2-start)<len1)   //即后面的长度不够匹配了,直接跳出ok
            return 0;           //表示匹配没有成功
    }
    return 0;
}

/*
    在匹配算法中花时间的部分是每次匹配不成功需要重新回到原匹配起点的下一个点
    Kmp算法就是在这个下一个匹配点的位置上做出改进,改进的想法是先对目标串生
    成一个最大前缀数组,也就是我们说的next数组,然后每次比较到一个不同的地方
    时就可以不用回溯,直接使用next函数
*/
//基本的KMP算法
//获取最大前缀匹配数组,str是后面的模式串
int getNext(char *str,int *next)
{
    next[0]=-1;
    next[1]=0;
    int len=strlen(str);
    int i=0;
    int j=0;
    int num=0;  
    for(i=2;i<len;i++)
    {
        if(str[i-1]==str[next[i-1]])
            next[i]=next[i-1]+1;
        else
            next[i]=0;
    }
    return 0;
}


int KmpMatch(char *a,char *b)
{
    int len1=strlen(a);
    int len2=strlen(b);
    int *next=(int *)malloc(sizeof(int)*len1);
    getNext(a,next);            //先获取模式串的前缀数组
    int i=0,j=0;
    while(i<len1&&j<len2)       //可以很清楚的看到j没有向前回溯,一直往后移动
    {
        if(a[i]==b[j])
            i++,j++;            
        else
            i=next[i];
        if(i==-1)
            i++,j++;      //如果第一个点就不匹配,则目标串向后面移动一位
        if(i==len1) 
            return j-len1;
    }
    return 0;
}


/*
    接下来就是改进的kmp算法,kmp算法在匹配过程中移动并不是最优的
    所以需要进一步改进,同样的最重要的还是next函数,改进后的next函
    数是避免了比较的重复,比如字符串ababc
    例如比配到第二个b不相同时,按原来的next函数是回到str[1]='b',
    即前一个b,依然是不相同的,再回到str[0]=a,这样就多余了,直接在
    后面判断,就可以直接回到a,免去了这一步.下面给出代码
*/  
int E_getNext(char *str,int *next)
{
    int len=strlen(str);
    next[0]=-1;
    int i=0,j=-1;
    while(i<len)
    {
        if(j==-1 || str[i] == str[j])
        {
            i++,j++;
            if(str[i]==str[j]) 
                next[i]=-1;     //这个就是后面的判断
            else
                next[i]=j;      //这个就是取的最大前缀
        }
        else
            j=next[j];
    }
    return 0;
}


int E_kmpMatch(char *a,char *b)
{
       int len1=strlen(a);
       int len2=strlen(b);
       int *next=(int *)malloc(sizeof(int)*len1);
       E_getNext(a,next);            //先获取模式串的前缀数组
      
       for(int tem=0;tem<len1;tem++)
           printf("%d ",next[tem]);
       printf("\n");

       int i=0,j=0;
       while(i<len1&&j<len2)       //可以很清楚的看到j没有向前回溯,一直往后移动
       {
           if(a[i]==b[j])
               i++,j++;            
           else
               i=next[i];
           if(i==-1) i++,j++;      //如果第一个点就不匹配
           if(i==len1) 
               return j-len1;
       }
    return 0;   
}

int main()
{

    char *a="ababac";
    char *b="ababcabcacb";
    int start = match(a,b);
    printf("start: %d\n",start);
    start = KmpMatch(a,b);
    printf("start: %d\n",start);
    start = E_kmpMatch(a,b);
    printf("start: %d\n",start);
    return 0;
}

 

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/qingtianweichong/article/details/8849932
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞