AC自動機的算法是構造壹棵Trie樹,然後添加額外的不匹配指針。這些額外的自適應指針允許在字符串搜索失敗時(比如Trie樹找不到單詞bef後,但單詞bea存在於Trie樹中,不匹配指針會指向前綴be),轉向壹些前綴分支,避免重復匹配前綴,從而提高算法的效率。
IDS軟件或病毒檢測軟件中常見的病毒特征串可以用來構造AC自動機。在這種情況下,算法的時間復雜度是輸入字符串的長度和匹配數之和。
假設現有的模式字符串集合:{Abd,Abdk,Abchijn,chnit,Ijabdf,Ijaij},AC自動機的構造如下:
描述:
1)當前指針curr指向AC自動機的根節點:curr=root。
2)從文本串中讀出(向下)壹個字符。
3)從當前節點的所有子節點中找到與該字符匹配的節點:
4)如果fail == null,說明沒有子串作為輸入字符串的前綴,那麽設置curr = root,執行步驟2。
如果失敗!= null,curr指向失敗節點,指向步驟3。
理解起來很復雜。我們舉壹個互聯網上的例子,假設文本字符串text = "abchnijabdfk "。
搜索過程如下:
解釋如下:
1)遍歷到:a-> b->;c->;H,此時發現文本串中的下壹個節點N與Trie樹中的下壹個節點I不匹配,H的fail指針不為空,跳轉到Trie樹中的ch位置。
註意c-> H不是結束節點,C的fail指針也不是結束節點。
2)然後遍歷n-> I,如果發現在Trie樹的下壹個節點找不到J,並且有fail指針,我就繼續遍歷。
在遍歷到D時,需要註意D的下壹個匹配節點F是結束字符,所以匹配字符串是ijabdf,D的失敗節點也是D和結束字符,所以得到匹配字符串abd,但不是失敗匹配,所以curr不跳轉。
首先將目標字符串插入到Trie樹中,然後通過有限廣度遍歷為每個節點的所有子節點找到正確的失效指針。
具體步驟如下:
1)將根節點所有子節點的fail指針指向根節點,然後依次對根節點的所有子節點進行排隊。
2)如果隊列不為空:
2.1)出隊壹個字符,記錄出隊節點為curr,failTo表示curr。
失敗指針,即failTo = curr.fail
2.2)判斷curr.child[i] == failTo.child[i]是否為真:
已建立:貨幣。孩子[我]。失敗=未能。孩子[我]
因為當前字符串的後綴和輪胎樹的前綴的最長部分將失效,
並且子字符與failTo的下壹個字符相同,則失敗指針為
failTo.child[i].
未建立:判斷failTo是否為空;
已建立:curr.child[i]。fail = root = null。
未建立:failTo = failTo.fail to繼續2.2
Curr.child[i]排隊,再次執行步驟2)。
3)隊列為空。
每個節點失效點的求解順序是按照有限廣度遍歷的順序完成的,或者按照順序遍歷的順序完成的。我們根據父節點的失效指針找到當前節點的失效指針。
以上圖為例,我們想解決Y節點的fail指針問題。我們已經知道Y節點的父節點x1的故障指向x2。根據fail指針的定義,我們知道紅色橢圓中的字符串序列必須相等,並且是最長的公共部分。根據y.fail的含義,如果x2的壹個子節點和節點Y所代表的字符相等,Y的fail就指向它。
如果節點Y所代表的字符不存在於x2的子節點中。由於x2.fail指向x3,根據x2.fail的含義,我們知道綠框中的字符序列是相同的。顯然,如果x3的壹個子節點和節點Y表示相等的字符,y.fail指向它。
如果x3的子節點沒有節點Y所代表的字符,我們重復這個步驟,直到xi的fail節點指向null,也就是說我們已經到了頂層,只要y.fail= root。
構造過程是當當前節點的最長公共前綴已知時,確定子節點的最長公共前綴。
下圖中,每個節點都有壹條失敗虛線,但是指向根節點的虛線沒有畫出來。找出圖中C的子節點H的失效方向:
在原圖中,深藍色方框表示故障指針已經確定。在紅框中找到H節點的失效指針。
這時我們來看H的父節點C的fail指針,它是ch中的C(這意味著abc字符串的所有後綴bc和C以及Trie樹的所有前綴中最長的public * * *部分都是C),而這個C節點的子節點有字符H,所以圖中紅框框中H節點的fail指針指向ch字符串中的H。
在紅框中找到I的失效指針。在上圖中,我們可以看到I的父節點H指向ch中的H(也就是說,我們的目標字符串組合中的字符序列abch的所有前綴和所有後綴在Trie樹中都有最長的前綴ch。)我們將節點I與ch中H的所有子節點進行比較,發現H只有壹個N的子節點,所以沒有辦法匹配。然後我們繼續在ch中尋找H的fail指針,圖中沒有顯示,所以它的fail指針是root,然後我們會看root的所有子節點是否都等於I,發現最右邊的I等於我們要找的I,於是我們將I的fail指針指向I,如下圖所示。