KMP算法

经过几个日日夜夜间断的努力,终于搞明白所谓的KMP算法了。

首先解释下KMP算法:它的目的是为了提取字串,解决了暴力(Brute-Force)算法冗余的指针回溯,从而提高了算法性能。其主要使用《算法导论》中的next数组,加速匹配。

举个栗子:
母串:abcabcabcabcabcd
子串:abcabcd

初始代码写手大概回使用如下的匹配方式:

		do
			abcabcabcabcabcd
			abcabcd(d!=a ==> 母串指针+1)
			abcabcabcabcabcd
			 a(a!=b ==>母串指针+1)
		loop

可是对比字串、母串的结构发现,最优的对比方式应该是:

		do
			abcabcabcabcabcd
			abcabcd(a!=d ==> 母串指针+3)
			abcabcabcabcabcd
			   abcabcd(a!=d ==> 母串指针+3)
		    abcabcabcabcabcd
	    		  abcabcd(a!=d ==> 母串指针+3)
		loop

那么疑问来了,经过我们观察,知道该字串可自增3来提高算法性能。一个未知的字串怎么计算呢?即:如何跳过字串重复部分来进行比较。

《算法导论》中指出:可使用next数组解决该问题。

先上代码:

void make_next(const char *pattern, int *next) {

    int q, k;
    int m = strlen(pattern);

    next[0] = 0; // 
    for (q = 1,k = 0;q < m; q ++) {

        while (k > 0 && pattern[q] != pattern[k]) {
            k = (next[k-1]-1)+1;
        }

        if (pattern[q] == pattern[k]) { 
            k ++;
        }

        next[q] = k;
        
    }
}

该算法原理:
在pattern中找到与其前缀相同的最大字符串的最后一个字符的位置,将之记录。在接下来寻找pattern位置时候,从前往后遍历,当发现pattern与text不能够匹配的时候,直接回溯pattern与当前匹配位置相匹配的前缀位置进行比较。

int kmp(const char *text, const char *pattern, int *next) {

    int n = strlen(text);
    int m = strlen(pattern);

    make_next(pattern, next);

    int i, q;
    for (i = 0, q = 0;i < n;i ++) { //i --> text, q --> pattern

        while (q > 0 && pattern[q] != text[i]) {
            q = (next[q-1]-1) + 1;
        }

        if (pattern[q] == text[i]) {
            q ++;
        }
        // q == m --->  
        if (q == m) {
            return i-q+1;
        }
    }
    return -1;
}

解释

k = (next[k-1]-1) + 1;   
q = (next[q-1]-1) + 1;

next[]-1是因为存储该位置时候先进行了k++,即记录的是匹配位置的下一个字符坐标。 next[] - 1 是为了找到最后匹配位置坐标。 (next[]-1) + 1 为了获取下一个字符坐标,为了与当前text做比较。

有兴趣可以加qq群:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值