分享一下字符串匹配BM算法学习心得。
字符串匹配BM(Boyer-Moore)算法學(xué)習(xí)心得
BM算法 是 Boyer-Moore算法 的縮寫,是一種基于后綴比較的模式串匹配算法。BM算法在最壞情況下可以做到線性的,平均情況下是亞線性的(即低于線性)。這也是他在實(shí)際應(yīng)用中優(yōu)于KMP算法的一個(gè)原因吧。
最近突然在看[柔性字符串匹配].[Flexible.Pattern.Matching.in.Strings](Gonzalo.Navarro,.Mathieu.Raffinot),想了解一下字符串匹配的一些算法,以前使用的算法基本都只是和ACM有關(guān)的,而且在單串匹配的情況下一般都只用KMP算法,而在這本書中對(duì)KMP算法的評(píng)價(jià)并不是很好,原因主要是出于工程上的“實(shí)用”上的原因吧。KMP算法雖然在理論上最壞復(fù)雜度也是線性的,可是在實(shí)際應(yīng)用中并沒有那么多最壞情況,而且如果用于模式匹配的話,很多情況下模式串也是很短的。
下面來說一說我寫這個(gè)的原因吧,我搞了兩年ACM嘛,現(xiàn)在看書肯定還是和ACM有一定關(guān)系的,而且很自然的會(huì)將一些事情和ACM中做對(duì)比的。[柔性字符串匹配]說KMP在實(shí)際應(yīng)用中不好,那我就想反過來看一下在實(shí)際應(yīng)用中比較好的算法在ACM中效果怎么樣了,最先看到的就是BM算法(當(dāng)然在書中還看到了Shift-or 和Shift-and 算法,但由于長度限制差別太大,實(shí)在不具可比性,不過這兩個(gè)算法個(gè)人感覺是相當(dāng)優(yōu)雅的)。由于這本書太實(shí)用了,對(duì)于“不實(shí)用”的算法都只做基本介紹(對(duì)于KMP算法也一樣,只做了一點(diǎn)大概的介紹,其實(shí)我非常不明白為什么會(huì)出現(xiàn)這種現(xiàn)象,難道理論和應(yīng)用的差別有這么大么?)。書上說原始BM算法在最壞情況下復(fù)雜度是O(n*m)的,O(n*m)的算法在ACM中必然是不“實(shí)用”的,但它說BM算法有兩個(gè)優(yōu)化版本可以在最壞情況下也能達(dá)到線性的。這樣一來我覺得就有一定可比性了,于是就想仔細(xì)看一下BM算法。
書上說的兩個(gè)算法是:the Boyer-Moore-Galil [Gal79] and the Turbo-BM[CGR92] algorithms。
我找了找,也沒找到什么相關(guān)資料,但是回頭一想這個(gè)算法都出來這么久了,直接搜BM算法應(yīng)該也能搜出優(yōu)化過的BM算法吧。
下面是我找到的一些文章。
?
字符串匹配那些事(一)
這篇文章好像是淘寶的吧,其中沒有明確指出BM算法的時(shí)間復(fù)雜度。
M模式匹配算法原理(圖解)
這篇文章對(duì)BM進(jìn)行了大致的講解,文中分析到了時(shí)間復(fù)雜度,
文中為:最好情況下的時(shí)間復(fù)雜度為O(n/m),最壞情況下時(shí)間復(fù)雜度為O(m·n)。
精確字符串匹配(BM算法)??BM 算法中“好后綴”預(yù)處理
在第一篇文章中提到了時(shí)間復(fù)雜度:整個(gè)算法的時(shí)間復(fù)雜度最壞的情況是 O(m),m 是 T 的長度。
可有一點(diǎn)我不明白,按這篇文章中的作法,好像并沒有對(duì)原始的BM算法進(jìn)行優(yōu)化,而原始的BM算法確實(shí)是O(m·n)的。
?
又重新去搜論文了。
A Fast String Searching Algorithm?- The University of Texas at Austin
Boyer-Moore-Galil?[Gal79]?Z. Galil. On improving the worst case running time of the Boyer-Moore string searching algorithm. Communications of the ACM, 22(9):505–508, 1979.
看了一下這兩篇論文,看一下第一篇,實(shí)在太長了(其實(shí)只有11頁但相對(duì)于第二篇只有4頁)。然后果斷看第二篇,雖然已經(jīng)是三十多年前的論文了。
在這里費(fèi)話兩句,之前我因?yàn)椤度嵝宰址ヅ洹愤@本書說KMP不怎么實(shí)用,心里還感覺有點(diǎn)不爽,你說KMP不實(shí)用,那你拿一個(gè)實(shí)用且理論最壞復(fù)雜度為線性的算法讓我看看。再加上找了一天多也只有一些BM算法的原始版。看了上面的第二篇文章,實(shí)現(xiàn)了一下其中的算法并在POJ上試了試,果然沒問題。在這一刻我深深的折服于《柔性字符串匹配》了。這本書果然名副其實(shí)。值得推薦。
好了,費(fèi)話也就說這么多,接下來說點(diǎn)技術(shù)性的吧,看看Z. Galil. 是如何將BM的最壞情況復(fù)雜度降到線性的。在這里,我默認(rèn)大家是明白BM算法原理的。加上上面已經(jīng)有那么多文章是寫B(tài)M算法的了(如果需要,建議閱讀淘寶的那篇),我這里只討論的優(yōu)化了。
以下討論中,文本串用T表示,模式串用p表示。|S|表示字符串S的長度。默認(rèn)情況下,n=|T|,m=|p|
?
為什么原始的BM算法在最壞情況下是O(n*m)的呢?一個(gè)最簡單的實(shí)例就是 p=a^m,T=a^n。就是說模式串是由m個(gè)a組成,文本是由n個(gè)a組成,在這種情況下,找出所有匹配復(fù)雜度就是O(n*m)的。造成這種情況最主要的就是BM算法在向后滑動(dòng)的時(shí)候?qū)χ捌ヅ溥^的字符的利用率并不高,不像KMP,一旦匹配過,就不會(huì)再回過頭再匹配一次,這也是我感覺KMP相當(dāng)神的一點(diǎn)。
在此之前先討論幾個(gè)概念,一個(gè)是字符串的周期性。
直觀的理解就是類似:abcabcabcabc,aabaabaab...這樣的串,都是有周期性的。我們?cè)谶@里認(rèn)為這種模式串也具有周期性的——abcabcab,就是最一個(gè)重復(fù)單元是不完整的。這里的周期性指至少重復(fù)一次以上,這種串不算有周期性——abcdabc。隨便提一下,這樣的串不具有周期性——ababababc,這里的周期性是針對(duì)于整個(gè)字符串來說的。
對(duì)于具用周期性的模式串,記模式串的最小正周期長度為ord。
再引出一個(gè)定義:匹配塊,T中的一段匹配塊是一段連續(xù)的字符串,其中包含有匹配上的匹配串,并且這些匹配上的區(qū)域是相互重疊的并且盡可能向左右延伸。當(dāng)然在匹配塊中不包含多余的字符。舉一個(gè)例子。(這里對(duì)匹配塊的定義不準(zhǔn)確,大家明白這個(gè)意思就行了。)
p = aba
T = abababaabaaba
其中前面一部分就是一個(gè)匹配塊:abababa,后面的abaaba不算,因?yàn)槠ヅ渖掀ヅ浯疀]有相互重疊。
基于以下幾點(diǎn)討論,我們可以對(duì)BM算法進(jìn)行優(yōu)化。
(1)如果文本串中不含模式串,那么BM算法在最壞情況下的比較次數(shù)為7n次。
(2)BM算法的最壞情況復(fù)雜度為O(n+r*m),其中n為|T|,m為|p|,r為p在T中出現(xiàn)次數(shù)。
(3)如果在上式中r>2n/m,則p是具有周期性的。
(4)如果p不具周期性,那么BM算法在最壞情況下是線性的。
(5)記一個(gè)匹配塊中所有匹配上的位置為p0,p1,...,pk(以遞增方式排列),
那么對(duì)于0<i<=k,pi - p(i-1)=ord。而且每個(gè)匹配塊中的匹配可以做到線性。
(6)優(yōu)化之后的BM' 算法是O(n)的。
優(yōu)化方法:每次成功匹配以后,向右移ord,并且在這種情況下只匹配那ord個(gè)字符。
偽代碼如下:
2 for(k=0; k+|p|<=|T|; )
3 {
4 for(i=pn-1; i>=last && T[k+i]==p[i]; )
5 i--;
6 if( i<last )
7 { /// 成功匹配
8 last = |p| - ord;
9 k += ord;
10 }
11 else
12 { /// 匹配失敗
13 last = 0;
14 k += (BM算法中的移動(dòng)距離);
15 }
16 }
這里就是算法的核心了。這里 hust 有BM實(shí)現(xiàn)poj 3461的完整代碼。
這個(gè)優(yōu)化只要知道的話就很好做了,在已有的BM代碼上加兩行就實(shí)現(xiàn)了。
這個(gè)改進(jìn)之后的BM' 算法在最壞情況下是線性的。
下面是相關(guān)說明,論文上也有證明。這里以比較直白的方式對(duì)其進(jìn)行一些分析。
(1)如果文本串中不含模式串,那么BM算法在最壞情況下的比較次數(shù)為7n次。
這一條我也不知道怎么證明的,這里默認(rèn)他是正確的吧。論文上說比較復(fù)雜沒有介紹。
(2)BM算法的最壞情況復(fù)雜度為O(n+r*m),其中n為|T|,m為|p|,r為p在T中出現(xiàn)次數(shù)。
這里我們把所有的r次完整匹配取出來,總共r*m次比較。這里我們想像用這r次匹配上的位置(取最左端)把T分割成了r+1個(gè)部分。對(duì)于前r個(gè)部分,我們還需要在其右端加上(m-1)字符。這里的r+1個(gè)文本串已經(jīng)無法匹配上p了。所以這里可以直接使用(1)了。而這時(shí)的總長度約為(n+r*m),代入第一條可得總比較次數(shù)少于:
7*n + 8*r*m <- ( 7*(n+r*m) + r*m )
(3)如果在上式中r>2n/m,則p是具有周期性的。
這里可以用鴿籠原理。先討論當(dāng)r>n/m時(shí),即r*m>n。所有匹配的長度之和已經(jīng)大于了|T|,這時(shí),至少有兩個(gè)匹配上的串是互相重疊的。這樣,r>2*n/m就很好理解了吧,r*(m/2)>n,至少存在兩次匹配上的串是互相重疊的,并且,重疊部分大于m/2。這代表了什么含意呢?想像一下,一個(gè)字符串,可以通過平移一小段距離,使重疊的那一部分互相匹配。這可以推出這個(gè)串是具有周期性的。
(4)如果p不具周期性,那么BM算法在最壞情況下也是線性的。
這條可以用(3)的逆否命題得到:如果p不具有周期性,那么在上式中r<=2n/m。再代入(2)中表達(dá)式O(n+r*m)。可得此時(shí)BM算法復(fù)雜度O(3*n)即O(n)。
(5)記一個(gè)匹配塊中所有匹配上的位置為p0,p1,...,pk(以遞增方式排列)。那么對(duì)于0<i<=k,pi - p(i-1)=ord。
這一點(diǎn)顯然吧。其實(shí)我并不是特別明白論文中特意指出這一點(diǎn)的意義何在。
(6)BM' 算法是O(n)的。
在這一點(diǎn)的理解上,很接近第二步的分析。把所有的匹配塊提取出來,對(duì)于匹配塊來說匹配是線性的,匹配塊的總長是在O(n)級(jí)別的。這里需要說明一點(diǎn)的是匹配塊是可以相互重疊的,但重疊部分不會(huì)大于m/2。而在剩下部分的匹配依然是O(n)級(jí)別的,所以總的時(shí)間復(fù)雜度也是O(n)的。
?
最后加一點(diǎn)關(guān)于(4)點(diǎn)的討論:我之前有一個(gè)錯(cuò)誤的認(rèn)識(shí),我以為當(dāng)p=b+a^m,T=a^n 時(shí)BM算法也是O(n*m)的,但我分析錯(cuò)了一個(gè)地方,我以為當(dāng)每次匹配到p的最左邊的b時(shí),失敗后只向右跳一個(gè)字符,而實(shí)際情況是向右跳了串長這么多。對(duì)BM的理解不夠啊。
附上poj測(cè)試圖,雖然從這里看BM算法跑得比kmp慢了一點(diǎn),但我已經(jīng)很滿足了。
上面的兩份代碼是用BM實(shí)現(xiàn)的,下面兩份是用KMP實(shí)現(xiàn)的。
?
轉(zhuǎn)載于:https://www.cnblogs.com/a180285/archive/2011/12/15/BM_algorithm.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的分享一下字符串匹配BM算法学习心得。的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle VARRAY的实际应用简介
- 下一篇: 关于HtmlParser中Parser【