字符串匹配 之 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()

這裏寫圖片描述

參考

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