【大白话】只会开关机都能懂KMP算法

场景:

序号i012345678910
文本acccacccab
词语acccab
序号j012345

从 原始算法(BM算法) 到 智能算法(KMP算法)

要在文本中寻找我们想要查找的词语,计算机不能像人一样,明眼看过去就找到了,别无他法,只能逐字逐字的比对;
于是就有了BM算法:从 文[0] 到 文[10] (即对应的序号下面的字母),把每一个都假设是词语的开头,即 词[0] (对应的序号上面的字母) ,然后逐字比较下去,不对就换文本的下一个字当开头;直到在文本的某个位置 文[i],发现接下去的几个字都能与词语的每个字对应,于是就匹配成功!

我们在文本中找到了出现词语的位置

然而用多就发现BM算法缺少点机灵劲,比如上面文本与词语的比对,它一直比对到序号5的位置,发现“c”不和"b"一样

序号i012345678910
文本acccacccab
词语acccab
序号j012345

然后它就把文本的位置加1,换成下一个字当开头,开始新一轮比对

序号i012345678910
文本acccacccab
词语acccab
序号j012345

结果当然是发现不对,再接着下一个…于是一直匹配到一眼看过去就知道不对应的“ccc” 完了,才找到正确的。

序号i012345678910
文本acccacccab
词语acccab
序号j012345

假如中间"ccc"很长,它就会把很多功夫浪费在上面,即使在第一次的匹配时,就已经知道了文本的前5个"ac…c…ca"和词语的是一 一对应的。

如果换成智能算法,它会这么做,它会利用第一次匹配后所得的对应信息,知道文本前5个是“accca”,它会把下一次开头的位置,跳过中间漫长的不会对应的“c”们,从序号5的a开始,并且不再对文本的a<文[4]>和词语的a<词[0]>进行比对,因为已经知道了它会是个正确的开头,然后开始从文[5]和词[1]进行比对。匹配成功;

智能算法会根据它第一次匹配得到的信息,选择下一次开始匹配的位置;智能的地方如下:
第一次匹配在文[i+m],词[m]出错,开始分析,前面所得匹配是否有可以当开头的位置,
1.假如有,那么当前出错位置,在词语里,该是序号几?

序号i01234*5678910
文本accc>a<*cccab
词语>a<*cccab
序号j0*12345

在文[4]为开头,那么在文[5]时,比对的应该是词[1];
智能算法的智能来自于一张智能表,依据此表,它可以算出,文本中的下一个开头位置为
文[ i+m-T[m] ] , 而当前文本出错位置该比对的词语位置为 词[T[m]]

该表英文名为"Partial match" Table (failure function),即 部分匹配表失配表),其实就是只匹配到一部分,或者失败时,会用到的表,此表T根据词语本身算出如下:

i012345
T[i]-1000-11

2.若前面并没有可以开头的,那么当前出错位置可否?
从T表中我们可以发现,若出错位置 词[0]=词[m] ,即出错位置字母等于开头字母的话,开头对应的T[i]为 -1,即算法放弃出错位置的尝试开头,跳到下一个开。要是不为开头字母的话,则文本从出错位置T[i+m],词语从 词[0]开始比对。对应的T[i]为0.

智能表的建立

观察算法对表的运用,无非是表T[i]决定了出错位置字符在前面已比对字串里的位置,
出错位置和它前面的n个字母 是否能够组成 词语的开头和接下去的n个字,一条n+1的相似链,是的话则这个相似链加1,不是则相似链截断,因为对它以及后面的字母来说,已经没有机会加入到这条长链,(然而萎缩后更短的链还有机会)

T[i]就是链身最长长度。由于数组从0开始,所以T[i]也是尚未与链身相接的链头位置。
文本新开头的比对词语的位置就是在这,它前面是已经确定一样了的链身

伪代码:

let T[0] ← -1    pos ← 1   atv ← 0

    while pos < length(W) do  (比对位pos,词语w)
        if W[pos] = W[atv] then 	(比对位==链头,链头接入链身成功)
            let T[pos] ← T[atv]	   (由于和开头的第n个一样,此处等同第n个作出的选择)
        else
            let T[pos] ← atv  (接入失败,相似链断裂,比对位等于最后链头位置)
            let atv ← T[atv]   (相似链萎缩至上一个链身)
            while atv ≥ 0 and W[pos] != W[atv] do (当未归负,假如链身和比对位字符不一样,继续萎缩)
                let atv ← T[atv]
        let pos ← pos + 1, atv ← atv + 1 (链长加1,比对位加1)

    let T[pos] ← atv (only need when all word occurrences searched)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值