字符串匹配:BF算法,KMP算法

一、BF 算法:
朴素匹配(暴力匹配)
主要思想:
从指定pos位置开始匹配,主串指针i初始为pos、子串指针j 初始为0;

1、开始匹配:主串、子串分别指向的当前元素进行比较,
相同,则i、j 同时后移一位
不同,则i 会退至开始位置的后一位、j 回退至0(子串首元素);

2、继续开始下一次匹配;

3、结束判断:
当子串j 后移至尾部,则匹配成功
当主串i 后移至尾部,且子串j 没有移至尾部,则匹配失败。

int BF(Str *s,Str *sub,int pos)//朴素匹配
{
    assert(s != NULL && sub != NULL);
    int i = 0;
    int j = 0;
    if(pos < 0 || pos > s->length || pos + sub->length > s->length)
    {
        return -1;
    }//判断pos位置是否有效
    //开始匹配
    while(i < s->length && j < sub->length)
    {
        if(s->elem[i] = sub->elem[j])
        {
            i++;
            j++;
        }
        else
        {
            i = i - j + 1;
            j = 0;
        }
    }
    //判断是否完全匹配:sub 能遍历结束则完全匹配
    if( j = sub->length)
    {
        return i - j;
    }
    else
    {
        return -1;
    }
}

二、KMP算法:
主要思想:
核心在于next数组 : next[j] = k(保存j 需要回退的位置)
(即当匹配失败时,主串i 不用回退,只需要当前的j 回退至next数组中保存的 k 值)。

k 值计算规则:
1、next[0] = -1 (一开始就匹配失败),next[1] = 0 (仅0号下标匹配成功);

2、在子串j 指向当前元素之前的部分子串中判断下标以0开头的真子串 == 下标以j-1结尾的真子串 是否存在,
存在,则当前的next[j] = 真子串的长度
不存在 , 则当前的next[j] = 0;

依据主串s,子串p:
假定p0…pk-1 = px…pj-1,
那么 k-1 = j-1-x , x = j-k,
则 p0…pk-1 = pj-k…pj-1

static void GetNext(int *next,Str *sub)//next数组
{
    next[0] = -1;
    next[1] = 0;
    int i = 2;//当前的i
    int k = 0;//前一项的K值
    while(i < sub->length)
    {
        if(k == -1 || sub->elem[i-1] == sub->elem[k])
        {
            next[i] = k+1;
            i++;
            k = k+1;//k++;
        }//没有真子串时赋0 / 有真子串时保存其长度至数组,并用k 保存其当前长度(若i++后仍匹配则直接在当前k基础上+1else
        {
            k  = next[k];
        }//(反之,若i++后不匹配则将k 归零,重新计算真子串长度)
    }
}

int Kmp(Str *s,Str *sub,int pos)
{
    if(pos < 0 || pos > s->length || pos + sub->length > s->length)
    {
        return -1;
    }//判断pos位置是否有效
    int i = pos;
    int j = 0;

    int *next = (int *)malloc(sizeof(int) * sub->length);
    assert(next != NULL);
    GetNext(next,sub);//得到next数组,用于定位匹配失败时j 回退的位置
    //开始匹配
    while(j < sub->length && i < s->length)
    {
        if(j == -1 || s->elem[i] == sub->elem[j])
        {
            i++;
            j++;
        }//匹配成功
        else
        {
            j = next[j];
        }//匹配失败,j 需要回退至k
    }
    //判断是否完全匹配
    if(j >= sub->length)
    {
        return i-j;
    }
    else
    {
        return -1;
    }
}

三、对于next数组的优化:
nextval数组(对于回退后认为与回退前字符相同的情况下,则直接将其回退至首次回退的地方,进而可以减少一部分多余的字符匹配比较)

四、BF算法与KMP算法的比较:
m代表主串长度,n代表子串长度,
1、BF算法:
时间复杂度为 O(mn)
算法思想:匹配失败时,主串 i、子串 j 均回退,且 j 每次都回退至子串首元素位置

2、KMP算法:
时间复杂度为 O(m+n)
算法思想:匹配失败时,主串 i 不回退、仅子串 j 回退,且 j 只需回退至 k

因此,KMP算法比BF算法尤为高效。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值