AC自動機(Aho-Corasick automation)

來源:互聯網
上載者:User

AC自動機:Aho-Corasick automation,該演算法在1975年產生于貝爾實驗室,是著名的多模匹配演算法。

解決的問題:給出n個單詞,再給出一段包含m個字元的文章,讓你找出有多少個單詞在文章裡出現過。(也是解決web開發中關鍵字連結的常用演算法:n個關鍵字,1篇文章,找出關鍵字在文章出現的位置)

思路:在一棵trie樹上面做Kmp,每個節點都有個像Kmp一樣匹配失敗時的指標(失敗指標),匹配失敗時按照失敗指標指向的節點繼續匹配。

要搞懂AC自動機,先得有模式樹(字典樹)Trie和KMP模式比對演算法的基礎知識。AC自動機演算法分為3步:構造一棵Trie樹,構造失敗指標和模式比對過程。KMP中我們用兩個指標i和j分別表示,A[i-j+ 1..i]與B[1..j]完全相等。也就是說,i是不斷增加的,隨著i的增加j相應地變化,且j滿足以A[i]結尾的長度為j的字串正好匹配B串的前 j個字元,當A[i+1]≠B[j+1],KMP的策略是調整j的位置(減小j值)使得A[i-j+1..i]與B[1..j]保持匹配且新的B[j+1]恰好與A[i+1]匹配,而next函數恰恰記錄了這個j應該調整到的位置。同樣AC自動機的失敗指標具有同樣的功能,也就是說當我們的模式串在Tire上進行匹配時,如果與當前節點的關鍵字不能繼續匹配的時候,就應該去當前節點的失敗指標所指向的節點繼續進行匹配。

例子:給定5個單詞:say she shr he her,然後給定一個字串yasherhs。問一共有多少單詞在這個字串中出現過。先規定AC自動機所需要的資料結構。

1 const int kind = 26; 
2 struct node{  
3     node *fail;           //失敗指標
4     node *next[kind];     //Tire每個節點的個子節點(最多個字母)
5     int count;            //是否為該單詞的最後一個節點
6     node(){               //建構函式初始化
7         fail=NULL; 
8         count=0; 
9         memset(next,NULL,sizeof(next)); 
10     } 
11 }*q[500001];              //隊列,方便用於bfs構造失敗指標
12 char keyword[51];         //輸入的單詞
13 char str[1000001];        //模式串
14 int head,tail;            //隊列的頭尾指標

首先,將這5個單詞構造成一棵Tire,。

在構造完這棵Tire之後,接下去的工作就是構造下失敗指標。構造失敗指標的過程概括起來就一句話:設這個節點上的字母為C,沿著他父親的失敗指標走,直到走到一個節點,他的兒子中也有字母為C的節點。然後把當前節點的失敗指標指向那個字母也為C的兒子。如果一直走到了root都沒找到,那就把失敗指標指向root。具體操作起來只需要:先把root排入佇列(root的失敗指標指向自己或者NULL),這以後我們每處理一個點,就把它的所有兒子排入佇列,隊列為空白。

1 void build_ac_automation(node *root){
2     int i;
3     root->fail=NULL; 
4     q[head++]=root; 
5     while(head!=tail){ 
6         node *temp=q[tail++]; 
7         node *p=NULL; 
8         for(i=0;i<26;i++){ 
9             if(temp->next[i]!=NULL){ 
10                 if(temp==root) temp->next[i]->fail=root;                 
11                 else{ 
12                     p=temp->fail; 
13                     while(p!=NULL){  
14                         if(p->next[i]!=NULL){ 
15                             temp->next[i]->fail=p->next[i]; 
16                             break; 
17                         } 
18                         p=p->fail; 
19                     } 
20                     if(p==NULL) temp->next[i]->fail=root; 
21                 } 
22                 q[head++]=temp->next[i];  
23             } 
24         }   
25     } 
26 }

從代碼觀察下構造失敗指標的流程:對照圖-2來看,首先root的fail指標指向NULL,然後root入隊,進入迴圈。第1次迴圈的時候,我們需要處理2個節點:root->next[‘h’-‘a’](節點h) 和 root->next[‘s’-‘a’](節點s)。把這2個節點的失敗指標指向root,並且先後進入隊列,失敗指標的指向對應圖-2中的(1),(2)兩條虛線;第2次進入迴圈後,從隊列中先彈出h,接下來p指向h節點的fail指標指向的節點,也就是root;進入第13行的迴圈後,p=p->fail也就是p=NULL,這時退出迴圈,並把節點e的fail指標指向root,對應圖-2中的(3),然後節點e進入隊列;第3次迴圈時,彈出的第一個節點a的操作與上一步操作的節點e相同,把a的fail指標指向root,對應圖-2中的(4),併入隊;第4次進入迴圈時,彈出節點h(圖中左邊那個),這時操作略有不同。在程式運行到14行時,由於p->next[i]!=NULL(root有h這個兒子節點,圖中右邊那個),這樣便把左邊那個h節點的失敗指標指向右邊那個root的兒子節點h,對應圖-2中的(5),然後h入隊。以此類推:在迴圈結束後,所有的失敗指標就是圖中的這種形式。

最後,我們便可以在AC自動機上尋找模式串中出現過哪些單詞了。匹配過程分兩種情況:(1)當前字元匹配,表示從當前節點沿著樹邊有一條路徑可以到達目標字元,此時只需沿該路徑走向下一個節點繼續匹配即可,目標字串指標移向下個字元繼續匹配;(2)當前字元不匹配,則去當前節點失敗指標所指向的字元繼續匹配,匹配過程隨著指標指向root結束。重複這2個過程中的任意一個,直到模式串走到結尾為止。

1 int query(node *root){ 
2     int i=0,cnt=0,index,len=strlen(str); 
3     node *p=root;  
4     while(str[i]){  
5         index=str[i]-'a';  
6         while(p->next[index]==NULL && p!=root) p=p->fail; 
7         p=p->next[index]; 
8         p=(p==NULL)?root:p; 
9         node *temp=p; 
10         while(temp!=root && temp->count!=-1){ 
11             cnt+=temp->count; 
12             temp->count=-1; 
13             temp=temp->fail; 
14         } 
15         i++;                 
16     }    
17     return cnt; 
18 }

對照圖,看一下模式比對這個詳細的流程,其中模式串為yasherhs。對於i=0,1。Trie中沒有對應的路徑,故不做任何操作;i=2,3,4時,指標p走到左下節點e。因為節點e的count資訊為1,所以cnt+1,並且講節點e的count值設定為-1,表示改單詞已經出現過了,防止重複計數,最後temp指向e節點的失敗指標所指向的節點繼續尋找,以此類推,最後temp指向root,退出while迴圈,這個過程中count增加了2。表示找到了2個單詞she和he。當i=5時,程式進入第5行,p指向其失敗指標的節點,也就是右邊那個e節點,隨後在第6行指向r節點,r節點的count值為1,從而count+1,迴圈直到temp指向root為止。最後i=6,7時,找不到任何匹配,匹配過程結束

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.