字符串匹配之朴素匹配&KMP匹配

在众多的语言编程里面有这么一个说法,看一个语言好不好,就看这个语言操作字符串方不方便,所以足以看出在计算机语言里面,操作字符串有多么重要,暂且不去说C语言中其他操作字符串的方法怎么样,今天就来说说字符串匹配的问题。
在C语言的string.h头文件中,char* strstr(const char*str,const char* src);这个方法就能实现这个问题,那么它是怎么实现的呢?今天就来说下这个。
在我的学习经历中,字符串匹配有两种算法,分别是朴素匹配KMP匹配这两种,待我一一道来。

朴素匹配

这种方法由叫做是暴力搜索,也是我们都能想到的方法。

基本思路

问题引入:由两个字符串str1和str2,str1的长度大于str2的长度,要求在str1中查找是否其中包含有字符串str2是它的子串,如果有就返回最后一个元素的下标(正整数),失败则返回-1。
方案:从str1和str2的第一个元素开始匹配,用i和j分别表示str1和str2的下标变化,如果元素相同就i++和j++,如果出现不同的情况,i = i-j+1,j=0;然后重新开始匹配。
《字符串匹配之朴素匹配&KMP匹配》
效率分析:最好的情况是,刚开始就能匹配到子串,那么它需要比较strlen(str2))次;最坏的情况是直到str1的最后一个元素才匹配完成或者没匹配到,这样的话比较(strlen(str1)-strlen(str2)+1)*strlen(str2)次,平均效率是O(strlen(str1)*strlen(str2))。
代码实现

int BF(const char*str,const char*sub,int pos)//字符串匹配
{
    if (pos <0)
    {
        return -1;
    }
    int str_len = strlen(str);
    int sub_len = strlen(sub);
    int str_i = pos;
    int sub_j = 0;
    while(str_i< str_len && sub_j < sub_len)
    {
        if (str[str_i] == sub[sub_j]) {
            sub_j++;
            str_i++;
        }
        else
        {
            str_i = str_i - sub_j + 1;
            sub_j = 0;
        }
    }
    if (sub_j == sub_len)
    {
        printf("find sub string\n");
        return sub_j;
    }
    printf("not find\n");
    return -1;
}

测试用例就不写了,这里主要讲算法!

KMP算法

这种字符串匹配方式的高效之处在于,如果匹配失败,每次不是重新从头开始匹配而是从之前已经准备好的数组中找到合适的位置重新开始匹配,这个数组在这里被称作是next数组。

当模式串的长度很小的时候,手动计算next数组也没什么问题。可手动计算终究不是办法,必须机器计算。实际上next数组可以递推求解,这也是一个理解上的难点。
(i)初始 next[0]=-1;
(ii)若next[j]为k,即有 P0…Pk-1(Pk…)=Pj-k…Pj-1(Pj…)(*式)(‘=’的意义:对应位置相匹配)。分两种情况,求解next[j+1]:
if(Pk==Pj),则 next[j+1]=k+1=next[j]+1; 道理显而易见:若Pk与Pj相等,则最长前后缀顺势增长一个,由*式可以看出。
若Pk与Pj不相等,则更新 k=next[k];if(Pk==Pj) next[j+1]=k+1;否则,重复此过程。(这里也是个匹配问题)
我们用手动计算得到的next数组,来进行下测试:
给定一主串 “cadabababcacadda”,模式串 “ababca”,next数组同上:next[]={-1,0,0,1,2,0}
《字符串匹配之朴素匹配&KMP匹配》
《字符串匹配之朴素匹配&KMP匹配》
不多说了,直接上代码!

基本实现

void GetNext(const char*str,int *next)//构造next数组
{
    int sub_len = strlen(str);
    next[0] = -1;
    next[1] = 0;
    int j=1;
    int k=0;
    while ((j+1)<sub_len)
    {
        if (k == -1 || str[j] == str[k])
        {
            next[++j] = ++k;
        }
        else
        {
            k = next[k];
        }
    }
}

int KMP(const char*str,const char*sub,int pos)
{
    if (pos < 0)
    {
        return -1;
    }
    int str_len = strlen(str);
    int sub_len = strlen(sub);
    int i = pos;
    int j = 0;
    int*next = (int*)malloc(sizeof(int)*sub_len);
    if (next == NULL)
    {
        return -1;
    }
    GetNext(sub,next);
    while (i < str_len && j < sub_len)
    {
        if (j == -1 || (str[i] == sub[j])) {
            i++;
            j++;
        }
        else
        {
            j = next[j];
        }
    }
    free(next);
    if (j == sub_len)
    {
        printf("find sub string\n");
        return j;
    }
    printf("not find\n");
    return -1;
}

测试用例

《字符串匹配之朴素匹配&KMP匹配》

暂时就这么多了,继续前进!

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