ref : https://dsqiu.iteye.com/blog/1700312html
本文內容框架:ios
§1 Boyer-Moore算法web
§2 Horspool算法算法
§3 Sunday算法數組
§4 KMP算算法數據結構
§5 KR算法框架
§6 AC自動機ide
§7 小結函數
§1 Boyer-Moore(BM)算法性能
Boyer-Moore算法原理
Boyer-Moore算法是一種基於後綴匹配的模式串匹配算法,後綴匹配就是模式串從右到左開始比較,但模式串的移動仍是從左到右的。字符串匹配的關鍵就是模式串的如何移動纔是最高效的,Boyer-Moore爲了作到這點定義了兩個規則:壞字符規則和好後綴規則,下面圖解給出定義:
下面分別針對利用壞字符規則和好後綴規則移動模式串進行介紹:
壞字符規則
1.若是壞字符沒有出如今模式字符中,則直接將模式串移動到壞字符的下一個字符:
(壞字符c,沒有出現模式串P中,直接將P移動c的下一個位置)
2.若是壞字符出如今模式串中,則將模式串最靠近好後綴的壞字符(固然這個實現就有點繁瑣)與母串的壞字符對齊:
(注:若是模式串P是babababab,則是將第二個b與母串的b對齊)
好後綴規則
好後綴規則分三種狀況
1.模式串中有子串匹配上好後綴,此時移動模式串,讓該子串和好後綴對齊便可,若是超過一個子串匹配上好後綴,則選擇最靠靠近好後綴的子串對齊。
2.模式串中沒有子串匹配上後後綴,此時須要尋找模式串的一個最長前綴,並讓該前綴等於好後綴的後綴,尋找到該前綴後,讓該前綴和好後綴對齊便可。
其實,1和2均可以當作模式串還含有好後綴串(好後綴子串也是好後綴)。
3.模式串中沒有子串匹配上後後綴,而且在模式串中找不到最長前綴,讓該前綴等於好後綴的後綴。此時,直接移動模式到好後綴的下一個字符。
Boyer-Moore算法步驟
1.對模式子串進行預處理
Boyer-Moore算法實現必須對模式串進行預處理,獲得壞字符規則和好後綴規則移動的映射表,下面代碼中MakeSkip是創建壞字符規則移動的映射表,MakeShift是創建好後綴規則的移動映射表。
MakeSkip是構造數組skip[],skip[k]表示字符k距離模式串末尾的距離。
MakeShfit是構造數組shfit[],shfit[k]表示模式串的以k爲邊界的後綴子串的最靠近的模式子串(或最前綴子串)到模式子串末尾的距離,例如:abcab,shfit[3]=3和shfit[2]=3(即都是第一個b到末尾的距離),k=2時,後綴子串爲cab,這時只有最長前綴ab,shfit[2]=3。
2.從b_idx開始查找,獲得壞字符和好後綴,獲得最大移動距離,移動b_idx,直至b_idx到達母串的末尾。
Boyer-Moore算法實現
算法的時間複雜度最差(匹配不上)是O(n×m),最好是O(n),其中n爲母串的長度,m爲模式串的長度。BM算法時間複雜度最好是O(n/(m+1))
§2 Horspool算法
horspool算法將主串中匹配窗口的最後一個字符跟模式串中的最後一個字符比較。若是相等,繼續從後向前對主串和模式串進行比較,直到徹底相等或者在某個字符處不匹配爲止(以下圖中的α與σ失配) 。若是不匹配,則根據主串匹配窗口中的最後一個字符β在模式串中的下一個出現位置將窗口向右移動。
Horspool算法相對於Boyer-Moore算法改進了壞字符規則,Boyer-Moore算法只是將模式串P中從當前未匹配位置向右第一個壞字符與母串的壞字符(未匹配的字符)對齊進行再次匹配,Horspool算法是以當前匹配窗口中母串的最末尾的一個字符和模式串最靠近它的字符對齊,下圖中β是當前匹配窗口的母串最後一個字符,將其與模式串左邊最靠近的β對齊移動。
Horspool算法預處理
爲了實現模式串的移動,必須先記錄每個字符串在模式串中距離最右邊的距離:
Horspool算法實現
Horspool算法時間複雜度
假設主串的長度爲n,模式串的長度爲m,那麼Horspool算法最壞狀況下的時間複雜度是O(mn),但平均狀況下它的時間複雜度是O(n)。
§3 Sunday算法
Sunday算法思想跟BM算法很類似,在匹配失敗時關注的是文本串中參加匹配的最末位字符的下一位字符。若是該字符沒有在匹配串中出現則直接跳過,即移動步長= 匹配串長度+1;不然,同BM算法同樣其移動步長=匹配串中最右端的該字符到末尾的距離+1。
Sunday算法實現
Boyer-Moore、Horspool、Sunday算法小結
Boyer-Moore、Horspool、Sunday算法都是基於後綴數組的匹配算法,區別在於移動的方式不同(好像網上有些都沒有說的Boyer-Moore算法的好後綴規則,有多是優化方法吧,沒有去深究,抱歉)。下面給出三種方法的對比:
In this example, t0, ..., t4 = a b c a b is the current text window that is compared with the pattern. Its suffix a b has matched, but the comparison c-a causes a mismatch. The bad-character heuristics of the Boyer-Moore algorithm (a) uses the "bad" text character c to determine the shift distance. The Horspool algorithm (b) uses the rightmost character b of the current text window. The Sunday algorithm (c) uses the character directly right of the text window, namely d in this example. Since d does not occur in the pattern at all, the pattern can be shifted past this position.
§4 Knuth-Morris-Pratt(KMP)算法
KMP算法是一種高效的前綴匹配算法,在傳統蠻力(BF)匹配算法的基礎上改進的地方在於每次移動的距離不是1能夠是更大,沒有進行回溯,BF算法的時間複雜度是O(m*n),而KMP算法的時間複雜度是O(m+n)。
假設執行第i+1趟匹配時,若是比較模式串P中的第j個字符時不匹配,也就是有
T[i,i+1,...,i+j-1]=P[0,1,...,j-1],T[i+j]≠P[j] (打不了下標,就有數組的形式給出字符串) (1)
BF算法下一趟是從目標的第i+1位置開始與模式串比較。若是匹配成功則有
T[i+1,i+2,...,i+m]=P[0,1,...m-1] (2)
若是模式串P有以下特徵
P[0,1,...j-2]=P[1,2,...j-1] (3)
由(1)可知
T[i+1,i+2,...,i+j+1]=P[1,2,...j-1] (4)
由(3)(4)可知
T[i+1,i+2,...,i+j+1]≠P[0,1,...j-2] (5)
故由
T[i+1,i+2,....,i+m]≠P[0,1,...m-1]
因此第i+2趟是匹配能夠不須要進行,由於必定不能匹配。
相似能夠推得
P[0,1,...k-1]=P[j-k-1,j-k,...j-1]
這時纔有
P[0,1,...k-1]=P[j-k-1,j-k,...j-1]=T[i+j-k,i+j-k+1,i+j-1]
模式串P從當前位置直接向右移動 j-k 位置,使模式串P的第 k 個字符P[k]與目標串T中的第i+j個字符對齊開始比較(前面 k 個已經匹配)。
形成BF算法效率低的主要緣由是在算法執行過程當中有回溯,而這些回溯是能夠避免的。KMP算法的關鍵是在匹配失敗時,肯定下一次匹配的位置,設next[j]=k,表示當模式串P中第j個字符與母串T相應字符不匹配時,模式串P中應當由第K個字符與目標串中剛不匹配的字符對齊繼續進行比較。
例如,模式串P="abaabcac",其對應的next[j]以下:
i |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
t[i] |
a |
b |
d |
a |
b |
c |
d |
e |
next[i] |
-1 |
0 |
0 |
0 |
1 |
2 |
0 |
0 |
next數組構造
╔ -1, j=0;
next[j]= ║max{k| 0<k<j 且 P[0,1,...,k-1]=P[j-k,j-k+1,..j-1}
╚ 0, 其餘狀況
next數組求解是一個遞推過程,
設next[j]=k,則有
P[0,1,...k-1]=P[j-k,j-k+1,...,j-1]
next[j]= ╔ max{k| 0<k<j 且 P[0,1,...,k]=P[j-k,j-k+1,..j-1}
╚ 0, 其餘狀況
若是P[k]=P[j],有 next[j+1]=next[j]+1=k+1。
若是P[k]≠P[j],有 P[0,1,...,k]≠P[j-k,j-k+1,...j],
假設next[j+1]=h+1,則有下式成立
P[0,1,...h]=P[j-h+1,j-k+1,...j] P[h]=P[j]
又由於
P[0,1,...h-1]=P[j-h,j-k+1,...j-1]=P[k-h,k-h+1,k-1] (next[k]=h的狀況)
即此時實際只須要知足 next[k]=h(前面已經求解過)時,P[h]=P[j] 就有next[j+1]=h+1,不然(不存在這樣的h)next[j+1]等於0。
由此能夠獲得計算next的遞推公式
KMP算法實現
§5 Karp-Rabin(KR)算法
Karp-Rabin算法是利用hash函數的特性進行字符串匹配的。 KR算法對模式串和循環中每一次要匹配的子串按必定的hash函數求值,若是hash值相同,才進一步比較這兩個串是否真正相等。
Karp-Rabin算法適用於多個字符串匹配較好。
§6 Aho-Corasick算法
Aho-Corasick算法又叫AC自動機算法,是一種多模式匹配算法。Aho-Corasick算法能夠在目標串查找多個模式串,出現次數以及出現的位置。
Aho-Corasick算法原理
Aho-Corasick算法主要是應用有限自動機的狀態轉移來模擬字符的比較,下面對有限狀態機作幾點說明:
上圖是由多模式串{he,she,his,hers}構成的一個有限狀態機:
1.該狀態當字符匹配是按實線標註的狀態進行轉換,當全部實線路徑都不知足(即下一個字符都不匹配時)按虛線狀態進行轉換。
2.對ushers匹配過程以下圖所示:
當轉移到紅色結點時表示已經匹配而且得到模式串
Aho-Corasick算法步驟
Aho-Corasick算法和前面的算法同樣都要對模式串進行預處理,預處理主要包括字典樹Tire的構造,構建狀態轉移表(goto),失效函數(failure function),輸出表(Output)。
Aho-Corasick算法包括如下3個步驟
1.構建字典樹Tire
2.構建狀態轉移表,失效函數(failure function),輸出表(Output)
3.搜索路徑(進行匹配)
下面3個步驟分別進行介紹
構建字典樹Tire
Tire是哈希樹的變種,Tire樹的邊是模式串的字符,結點就是Tire的狀態表,下圖是多模式串{he,she,his,hers}的Tire樹結構:
構建goto函數、failure function和Output函數
goto函數(狀態轉移函數):goto(pre,v)=next,完成這樣的任務:在當前狀態pre,輸入字符v,獲得下一個狀態next,若是沒有下個狀態則next=failure。
failure function:失效函數是處理當前狀態是failure時的處理。
output函數:當完成匹配是根據狀態輸出匹配的模式串。
下面是多模式串{he,she,his,hers}的goto函數,failure函數,output函數
goto函數:
failure函數
output函數
多模式串{he,she,his,hers}最終的有限狀態機圖
Aho-Corasick算法實現
§7 小結
這篇文章把字符串匹配的六個算法——BM、Horspool、Sunday、KMP、KR、AC算法,從原理到步驟,再從流程到實現都作了講解了,能有了必定的認識和理解,基本能夠掌握這些算法。若是你有任何建議或者批評和補充,請留言指出,不勝感激,更多參考請移步互聯網。
參考(後面3個連接很不錯的喲):①jijy:http://www.searchtb.com/2011/07/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8C%B9%E9%85%8D%E9%82%A3%E4%BA%9B%E4%BA%8B%EF%BC%88%E4%B8%80%EF%BC%89.html②ouyangjia7:http://ouyangjia7.iteye.com/blog/353137③那誰的技術博客:http://www.cppblog.com/converse/archive/2006/07/05/9447.html④CobbLiu:http://www.cnblogs.com/cobbliu/archive/2012/05/29/2524244.html⑤kmplayer:http://kmplayer.iteye.com/blog/704187⑥志文工做室:http://www.zhiwenweb.cn/Category/Security/1274.htm⑦http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm⑧http://www-igm.univ-mlv.fr/~lecroq/string/⑨http://www.csie.ntnu.edu.tw/~u91029/StringMatching.html