字串匹配演算法之aho-corasick2008-12-18 16:23
aho-corasick可以認為是kmp演算法在多串查詢的擴充套件。先把所有要查詢的串放在一起建一棵trie樹。然後從源串的各個位置開始的串到trie樹里查詢。這樣每次查詢的複雜度為o(m),m為最長的子串。總共要查n次,所以複雜度為o(nm)。這只能說是brute force演算法在多串下的擴充套件。所以還要在trie樹里新增一些轉移,使得源串在匹配過程中不出現回退。假設當前節點為i,源串匹配到字元c,如果節點i不存在c字母對應的轉移。這時候應該跳轉到乙個節點j,從trie樹根節點到這個節點的字母組成的字串,應該是從根節點組成的字串的字尾,如果有多個這樣的節點,則跳轉到最短的乙個。分析一下這個自動機在匹配時的複雜度。要匹配過程中,源串不回退,所以遍歷源串的複雜度為o(n)。但是在匹配失敗的時候,會出現跳轉,可能要跳轉很多次才可以匹配成功。但是注意一點,每次跳轉使得深度至少減1,而深度至多跟源串匹配的長度相等,所以可以跳轉的次數不會超過源串的長度,所以總的複雜度是o(n)。
要注意乙個地方,字尾關係是可以傳遞的,a是b的字尾,b是c的字尾,則a是c的字尾。所以上面的表示式,最終是把乙個串的後有字尾,從長到短串成了乙個鍊錶。
難的地方就是自動機的構造。為了便於分析,把建trie樹跟增加跳轉分成兩個過程。假設現在已經建好trie樹。要為乙個節點增加跳轉,最簡單的方法是,把根結點到它一路上的字串組成的字串,求字尾,再到trie樹里查詢,因為是求最長的字尾,所以從長到短,逐一去查詢,直至找到為止,找到的節點就是要跳轉的節點。這種方法的複雜度很高。觀察一下,假設在trie樹里,i節點是j節點的父結點,j的跳轉結點的父結點表示的串,也是i的字尾。反過來說,根據乙個節點的父結點的跳轉可以快速地找到這個結點的跳轉。假設當前節點的父結點的跳轉結點為k,下乙個要匹配的字元為c,看k是否有c的跳轉,如果沒有,則k繼續跳轉。會否出現沒有找到合法的跳轉,而k又不能再跳轉的情況呢?初始的時候,把所有節點的跳轉都指向根結點,可以避免這種情況。
在實現的時候,因為跳轉總是從深度大的結點跳到深度小的結點,所以對trie樹作廣度遍歷。現在來分析一下構造的複雜度。trie樹中結點的總數不會超過待查詢的子串的長度和。但是每個結點的查詢會進行多次跳轉。分析乙個子串它對應的一系列節點,每交跳轉會使得深度減1,而這些節點的深點至多為子典的長度,所以乙個子串對應的所有結點的構造費用之和,不會超過字串的長度,所以總的構造複雜度是跟字元長度和成正比的。
演算法之 字串匹配演算法
一說到兩個字串匹配,我們很自然就會想到用兩層迴圈來匹配,用這種方式就可以實現乙個字串是否包含另乙個字串了,這種演算法我們稱為 bf演算法。bf演算法,即暴力 brute force 演算法,是普通的模式匹配演算法,bf演算法的思想就是將目標串 s 的第乙個字元與模式串 t 的第乙個字元進行匹配,若相...
字串匹配演算法 字串匹配演算法總覽
字串匹配在文字處理裡非常重要,我們採用簡潔的python 把以下演算法一一實現並講解。樸素演算法 algorithm rabin karp 演算法 有限自動機演算法 finite automation knuth morris pratt 演算法 kmp algorithm boyer moore ...
字串匹配演算法之BF vs KMP
最笨的方法bf,暴力匹配,無需多說,最難理解的是kmp演算法,費了好大勁才弄明白。要理解kmp演算法,其實最關鍵的是生成標明下次匹配位置的next陣列。其意義是,如果當前匹配到模式字串的第j個字元是失配,則只需要將j重置為next j 後,繼續向後匹配即可。next j 的值表示p 0.j 1 中最...