KMP模式匹配算法

KMP算法主要解决的问题是如何较为高效地在主串中寻找指定的字串。这种算法可以大大避免朴素匹配中出现的重复遍历的情况。算法的实质是利用字子串自身所具有的一些特殊性质,得到一个函数返回函数Next,从而通过函数Next来避免大量重复遍历的情况。
下面先给出函数Next的定义:
对于字符串T(也可看成是字符列表)
N e x t [ j ] = { − 1 j = 0 m a x { k ∣ 0 &lt; k &lt; j   a n d   T [ 0 : k ] = T [ j − k : j ] } 当 此 集 合 不 为 空 时 0 其 他 情 况 Next[j]=\begin{cases} -1 &amp; j=0 \\ max\{k|0&lt;k&lt; j\ and\ T[0:k]=T[j-k:j]\} &amp;当此集合不为空时 \\ 0&amp;其他情况\\ \end{cases} Next[j]=1max{k0<k<j and T[0:k]=T[jk:j]}0j=0
定义的意义:设主串为 S S S,子串为 T T T,假设比较进行到了 S [ i ] , T [ j ] S[i],T[j] S[i],T[j]处,且 S [ i ] ! = T [ j ] S[i]!=T[j] S[i]!=T[j]
 1.当 j = 0 j=0 j=0时, N e x t [ j ] = − 1 Next[j]=-1 Next[j]=1,此时需要进行的比较为 S [ i + 1 ] S[i+1] S[i+1] T [ j + 1 ] T[j+1] T[j+1]
 2.当 { k ∣ 0 &lt; k &lt; j   a n d   T [ 0 : k ] = T [ j − k : j ] } \{k|0&lt;k&lt; j\ and\ T[0:k]=T[j-k:j]\} {k0<k<j and T[0:k]=T[jk:j]}不为空时,
按照 N e x t Next Next定义取 N e x t [ j ] = m a x { k ∣ 0 &lt; k &lt; j   a n d   T [ 0 : k ] = T [ j − k : j ] } Next[j]=max\{k|0&lt;k&lt; j\ and\ T[0:k]=T[j-k:j]\} Next[j]=max{k0<k<j and T[0:k]=T[jk:j]},因为对于 T [ 0 : j ] T[0:j] T[0:j]已经同 S [ i − j : i ] S[i-j:i] S[ij:i]比较过且相等,又因为 T [ 0 : k ] = T [ j − k : j ] T[0:k]=T[j-k:j] T[0:k]=T[jk:j],这意味着已经得到 S [ i − k : i ] = T [ 0 : k ] S[i-k:i]=T[0:k] S[ik:i]=T[0:k],故需要比较的只有 T [ k : ] T[k:] T[k:] S [ i : ] S[i:] S[i:],故此时 N e x t Next Next的意义是避免了对 T [ 0 : k ] T[0:k] T[0:k]做无谓的比较,让子串与主串的比较直接从子串的第k处开始。
 3.当为其他情况时,直接从头开始比较。

Next代码

def get_Next(T):
    
    j=0
    Next=[-1]
    for j in range(1,len(T)):
        
        K=[k for k in range(2,j+1) if T[0:k-1]==T[j-k+1:j] and k-1>0]
        if K:Next.append(max(K)-1)
        else:Next.append(0)

    return Next

完整代码

# -*- coding: utf-8 -*-
"""
Created on Fri Mar 15 10:14:32 2019

@author: Administrator
"""

def get_Next(T):
    j=0
    Next=[-1]
    for j in range(1,len(T)):
        K=[k for k in range(1,j) if T[0:k]==T[j-k:j] and k>0]
        if K:Next.append(max(K))
        else:Next.append(0)

    return Next

def Index_KMP(S,T,pos=0): 				#S:主串,T:子串,pos:在主串中开始搜寻的位置
    j=0
    i=pos
    Next=get_Next(T)
    while (i<len(S) and j<len(T)):

        if j==-1 or S[i]==T[j]:
        #即在上一次比较中发现子串T中第一个字母便与S[i]不同,或者是S[i]==t[j],则主串和子串的指标i,j均往后移1个位置
            i+=1
            j+=1
        else:
        #即j!=-1且S[i]!=T[j]
            j=Next[j]
    if j==len(T):
    #如果对于T比较完成,则返回主串中对应位置的开头
        return i-len(T)
    else:
        return -1
    
S='dasdfhaskaslsfkjhfweiu'
T='askasls'
Index_KMP(S,T,pos=0)

关于Next函数的改进 N e x t v a l Nextval Nextval

改进的实质:在S[i]!=T[j]时,在计算 N e x t Next Next的值的同时,如果 j j j位字符与它 N e x t Next Next值所指向的 N e x t [ j ] Next[j] Next[j]位字符相等,则该 j j j位的 N e x t v a l Nextval Nextval就指向 N e x t [ j ] Next[j] Next[j]位的 N e x t v a l Nextval Nextval值,这是因为 j j j位字符如果通过 N e x t Next Next回到前面的字符位置后,接下来要进行比较的就是 T [ N e x t [ j ] ] T[Next[j]] T[Next[j]] S [ i ] S[i] S[i],而我们已经比较得到 S [ i ] ! = T [ j ] S[i]!=T[j] S[i]!=T[j],故若 T [ j ] = T [ N e x t [ j ] ] T[j]=T[Next[j]] T[j]=T[Next[j]],则也有 T [ N e x t [ j ] ] ! = S [ i ] T[Next[j]]!=S[i] T[Next[j]]=S[i],故需要再次通过 N e x t Next Next返回,即返回至 N e x t [ N e x t [ j ] ] Next[Next[j]] Next[Next[j]];如果不相等,则 j j j位的 N e x t v a l Nextval Nextval值就是它自己 i i i位的 N e x t Next Next值。

Nextval代码

def get_Nextval(T):
    j=0
    Nextval=[-1]
    for j in range(1,len(T)):
        K=[k for k in range(1,j) if T[0:k]==T[j-k:j] and k>0]
        if K:
            if T[max(K)]==T[j]:Nextval.append(Nextval[max(K)])
            else:Nextval.append(max(K))
        else:
            if T[j]==T[0]:Nextval.append(-1)
            else:Nextval.append(0)
            
    return Nextval
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值