字符串匹配算法KMP

 

看了阮一峰的博客,然后找到了  关于KMP 算法相当详细的博客: https://blog.csdn.net/v_july_v/article/details/7041827

 

摘录:

  • 如果模式串中存在相同前缀和后缀,即pj-k pj-k+1, ..., pj-1 = p0 p1, ..., pk-1,那么在pj跟si失配后,让模式串的前缀p0 p1...pk-1对应着文本串si-k si-k+1...si-1,而后让pk跟si继续匹配。
  • 之前本应是pj跟si匹配,结果失配了,失配后,令pk跟si匹配,相当于j 变成了k,模式串向右移动j - k位。
  • 因为k 的值是可变的,所以我们用next[j]表示j处字符失配后,下一次匹配模式串应该跳到的位置。换言之,失配前是j,pj跟si失配时,用p[ next[j] ]继续跟si匹配,相当于j变成了next[j],所以,j = next[j],等价于把模式串向右移动j - next [j] 位。
  • 而next[j]应该等于多少呢?next[j]的值由j 之前的模式串子串中有多大长度的相同前缀后缀所决定,如果j 之前的模式串子串中(不含j)有最大长度为k的相同前缀后缀,那么next [j] = k。

 

kmp 

 

 

写了python的实现,记录一下:

  

  1 #!/usr/bin/env python
  2 #-*- coding: utf-8 -*-
  3 
  4 import array
  5 
  6 
  7 def bruteForce(text, p):
  8     out = []
  9     textLen = len(text)
 10     pLen = len(p)
 11 
 12     i = 0
 13     j = 0
 14 
 15     while(i < textLen):
 16         if text[i] == p[j]:
 17             i += 1
 18             j += 1
 19         else:
 20             print('i:%d\tj:%d' % (i,j))
 21             i = i - j + 1
 22             j = 0
 23 
 24         if j == pLen:
 25             out.append(i - pLen)
 26             j = 0
 27         else:
 28             continue
 29     return out
 30 
 31 #优化前next
 32 def getNext(p):
 33     pLen = len(p)
 34     next = [ -1 for x in xrange(pLen)]
 35 
 36     k = -1
 37     j = 0
 38 
 39     no = 0
 40 
 41     while(j < pLen -1):
 42         no  += 1
 43         print( 'NO.= %d, k= %d, j= %d' % (no, k, j) )
 44         #p[k]表示前缀,p[j]表示后缀
 45         if k == -1 or p[k] == p[j]:
 46             k += 1
 47             j += 1
 48             next[j] = k
 49         else:
 50             k = next[k]
 51     return next
 52 
 53 #优化后next
 54 def getNext2(p):
 55     pLen = len(p)
 56     next = [ -1 for x in xrange(pLen)]
 57 
 58     k = -1
 59     j = 0
 60 
 61     no = 0
 62 
 63     while(j < pLen -1):
 64         no  += 1
 65         print( 'NO.= %d, k= %d, j= %d' % (no, k, j) )
 66         #p[k]表示前缀,p[j]表示后缀
 67         if k == -1 or p[k] == p[j]:
 68             k += 1
 69             j += 1
 70             if p[k] != p[j]:
 71                 next[j] = k
 72             else:
 73                 #因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]
 74                 next[j] = next[k]
 75         else:
 76             k = next[k]
 77     return next
 78 
 79 
 80 def kmp(text, p, next):
 81     out = []
 82     textLen = len(text)
 83     pLen = len(p)
 84 
 85     i = 0
 86     j = 0
 87 
 88     while(i < textLen):
 89         #①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
 90         if j == -1 or text[i] == p[j]:
 91             i += 1
 92             j += 1
 93         else:
 94             #②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
 95             #next[j]即为j所对应的next值
 96             j = next[j]
 97 
 98         if j == pLen:
 99             out.append(i - pLen)
100             j = 0
101         else:
102             continue
103 
104     return out
105 
106 
107 if __name__ == '__main__':
108 
109     text = 'asdfabdewdadsabacababc'
110     p =    'ababc'
111 
112     textCharArray = array.array("B",text.strip())
113     pCharArray = array.array("B", p.strip())
114 
115     print(textCharArray)
116     print(pCharArray)
117 
118     #暴力匹配
119     #print(bruteForce(textCharArray, pCharArray))
120 
121     #kmp
122     #get next array
123     next = getNext2(pCharArray)
124     print(kmp(textCharArray, pCharArray, next))

 

posted @ 2019-01-02 18:17  jellyabd  阅读(161)  评论(0编辑  收藏  举报