字符串匹配 之 RK(Rabin-Karp)

背景

Rabin-Karp字符串匹配算法和前面介绍的《朴素字符串匹配算法》类似,也是对应每一个字符进行比较,不同的是Rabin-Karp采用了把字符进行预处理,也就是对每个字符进行对应进制数并取模运算,类似于通过某种函数计算其函数值,比较的是每个字符的函数值。预处理时间O(m),匹配时间是O((n-m+1)m)。

Rabin-Karp算法的思想:

  1. 假设待匹配字符串的长度为M,目标字符串的长度为N(N>M);
  2. 首先计算待匹配字符串的hash值,计算目标字符串前M个字符的hash值;
  3. 比较前面计算的两个hash值,比较次数N-M+1:
    • 若hash值不相等,则继续计算目标字符串的下一个长度为M的字符子串的hash值
    • 若hash值相同,则需要使用朴素算法再次判断是否为相同的字串;

伪代码

Rabin_Karp_search(T, P, d,  q)  
    n = T.length;  
    m = P.length;  
    h = d^(m-1)mod q;   
    p = 0;  
    t = 0;  
    for i =1 to m  
       p = (d*p+P[i]) mod q;  
       t = (d*t+T[i])mod q;  
    for i = 0 to n-m     
         if p==t  
             if P[1..m]==T[i+1..i+m]  
             print"Pattern occurs with shift"i  
         if i<n-m  
             t = d(t-T[i+1]h) + T[i+m+1]mod q  

其中

  • d表示字母表的字母个数,ascii值为0~127的字符。如果采用小写英文字母来做字母表的话,那么d就是26。
  • h=dm1%q 。其实模q运算应该是可有可无的,加入q应该是为了避免数据溢出。但是加入模q后,由ts == p mod q不能说明ts == p,不过ts != p mod q则可以肯定ts != p。所以q最好选择比较大的质数,并且选取的q要满足使d,q的值在一个计算机字长内。如果使用的是动态的编程语言的话就不用担心数据溢出,因此就不用进行模q运算。

代码实现

# -*- coding: utf-8 -*-
"""
Created on Thu Jul 28 23:11:27 2016

@author: zang
"""

def Rabin_Karp(text, pattern, d, q):
    n = len(text)
    m = len(pattern)
    h = pow(d,m-1)%q
    p = 0
    t = 0
    flag = 0
    results = []
    for i in range(m): # preprocessing
        p = (d*p+ord(pattern[i]))%q
        t = (d*t+ord(text[i]))%q
    for s in range(n-m+1): # note the +1
        if p == t: # check character by character
            match = True
            for i in range(m):
                if pattern[i] != text[s+i]:
                    match = False
                    break
            if match:
                flag += 1
                results.append(" "*s + pattern + " "*(n - m - s) + "  " + str(s+1) + "  " + str(flag))
        if s < n-m:
            t = (t-h*ord(text[s]))%q # remove letter s
            t = (t*d+ord(text[s+m]))%q # add letter s+m
            t = (t+q)%q # make sure that t >= 0
    if flag == 0:
        print "No find."
    else:
        print flag," matching results are listed below."
        print "-------" + "-"*t + "-------"
        print text
        for line in results:
            print line
        print "-------" + "-"*t + "-------"

def main():
    while 1:
        text = raw_input("text: ")
        pattern = raw_input("pattern: ")
        d = int(raw_input("charsize: "))
        q = int(raw_input("mod number: "))
        if len(text) == 0 or len(pattern) == 0:
            print "\nplease input text and pattern again!"
            break
        Rabin_Karp(text, pattern,d,q)

if __name__ == '__main__':
    main()

这里写图片描述

参考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章