1. 程式人生 > >18.12.30 【sssx】Trie圖

18.12.30 【sssx】Trie圖

輸入 小寫 new root eof set 遍歷 向上 trie

Trie樹(字典樹)

樹中任一結點p都對應於一個字符串S,S由從根出發走到p所經過的邊上的字符構成

數據結構

struct trienode
{
    trienode * child[26] ;
    //假設所有字符就是26個小寫字母
    trienode() {
        memset(child,0,
        sizeof(child));
    }
};

操作

插入串

 1 void build(string s, trienode * root)
 2 {
 3     trienode* p=root;
 4     for
(int i=0;i<s.size();++i) 5 { 6 if (p->child[s[i]-’a’]== NULL) 7 p->child[s[i] -’a’] = new trienode(); //初始化新的節點 8 p=p->child[s[i] -’a’]; 9 } 10 }

(復雜度為模式串長度)

Trie圖(AC自動機)

可以由Trie樹為基礎構造

終止節點:每個模式串最後一個結點

危險結點:終止節點和前綴指向危險結點的結點。

包含前綴指針(next),結點p(字符串為S)的前綴指針指向的結點q的字符串為T滿足:T是其他串中最長的S的一個後綴且不可等於S(可以為空串,即root)

求母串包含哪些模式串,將母串輸入在Trie圖上行走走到終止節點就表示匹配了相應的模式串

數據結構

int nNodesCount=0;
struct CNode
{
    CNode * pChilds[LETTERS];
    CNode * pPrev; //前綴指針
    bool bBadNode; //是否是危險節點
    CNode() {
        memset(pChilds,0,sizeof(pChilds));
        bBadNode 
= false; pPrev = NULL; } }Tree[MAXN];

操作

在Trie樹上添加前綴指針

  • 用BFS按深度由淺到深求每一個結點的前綴指針
  • 對於結點P,設其父節點與其連邊上的字符為ch,找到父節點的前綴指針指向的結點看它與兒子的邊有沒有一條是ch的,如果有就把這個兒子作為P的前綴指針指向,沒有繼續用這個結點的前綴指針向上找。
 1 void BuildDfa( ) { //在trie樹上加前綴指針
 2     for( int i = 0;i < LETTERS ;i ++ )
 3         Tree[0].pChilds[i] = Tree + 1;
 4         Tree[0].pPrev = NULL;
 5         Tree[1].pPrev = Tree;
 6         deque<CNode * > q;
 7         q.push_back(Tree+1);
 8         while( ! q.empty() ){
 9             CNode * pRoot = q.front();
10             q.pop_front();
11             for( int i = 0; i < LETTERS ; i ++ ) {
12                 CNode * p = pRoot->pChilds[i];
13                 if( p) {
14                     CNode * pPrev = pRoot->pPrev;
15                     while( pPrev->pChilds[i] == NULL)
16                         pPrev = pPrev->pPrev;
17                     p->pPrev = pPrev->pChilds[i];
18                     if( p->pPrev-> bBadNode)
19                         p-> bBadNode = true;
20                     //前綴指針指向的節點是危險節點,則自己也是危險節點
21                     q.push_back(p);
22                 }
23             }
24         } //對應於while( ! q.empty() )
25 }

母串匹配

  • 從root和母串第一個字符出發
  • 若當前點P不存在通過當前字符連接的兒子,則考察P的前綴指針指向的結點Q,依次類推直到找到。母串指針指向下一個字符繼續遍歷。
  • 如果遍歷過程中經過了某個終止結點,說明S包含該終止結點代表的模式串。
  • 若遍歷過程中經過了某個非終止結點的危險結點則可以順著前綴指針找到一個終止結點,這個終止結點代表的串被S包含。
  • 復雜度:S的長度
 1 bool SearchDfa(char * s)
 2 {//返回值為true則說明包含模式串
 3     CNode * p = Tree + 1;
 4     for( int i = 0; s[i] ; ++i) {
 5         while( p->pChilds[s[i]-a] == NULL)
 6             p = p->pPrev;
 7         p = p->pChilds[s[i]-a];
 8         if( p-> bBadNode)
 9             return true;
10     }
11     return false;
12 }

18.12.30 【sssx】Trie圖