matbensch

Aho-Corasick C++

Jan 29th, 2023 (edited)
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.72 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <unordered_map>
  4. #include <queue>
  5.  
  6. using namespace std;
  7.  
  8. struct node
  9. {
  10.     unordered_map<char,int> child; // map of child characters to index in trie array
  11.     bool leaf = false; // true if node corresponds to word, false otherwise
  12.     int parent = -1; // index of parent in trie array
  13.     char ch = '?'; // corresponding character
  14.     int suffix_link = -1; // index of suffix link
  15.     int dict_suffix_link = -1; // index of dict suffix link
  16.     int word_id = -1; // index of corresponding word in words array, if leaf
  17. };
  18.  
  19. struct aho
  20. {
  21.     vector<node*> trie;
  22.     vector<string> words;
  23.     int num_words = 0;
  24.     int size = 0;
  25.     int root;
  26.  
  27.     // trie insert
  28.     void insert(string s)
  29.     {
  30.         int cur = root;
  31.         for(char c : s)
  32.         {
  33.             if(trie[cur]->child.find(c) == trie[cur]->child.end())
  34.             {
  35.                 trie.push_back(new node());
  36.                 trie[size]->parent = cur;
  37.                 trie[size]->ch = c;
  38.                 trie[cur]->child[c] = size;
  39.                 size++;  
  40.             }
  41.             cur = trie[cur]->child[c];
  42.         }
  43.  
  44.         trie[cur]->leaf = true;
  45.         trie[cur]->word_id = num_words++;
  46.         words.push_back(s);
  47.     }
  48.  
  49.     aho()
  50.     {
  51.         root = 0;
  52.         trie.push_back(new node());
  53.         size++;
  54.     }
  55.  
  56.     void calc_suffix_link(int cur)
  57.     {
  58.         // base case: suffix link and dict suffix link are root
  59.         if(cur==root || trie[cur]->parent==root)
  60.         {
  61.             trie[cur]->suffix_link = trie[cur]->dict_suffix_link = root;
  62.             return;
  63.         }
  64.  
  65.         // parent's suffix link
  66.         int par_link = trie[trie[cur]->parent]->suffix_link;
  67.         // cur's character
  68.         char c = trie[cur]->ch;
  69.  
  70.         // move parent's suffix link until we reach root or contains c
  71.         while(true)
  72.         {
  73.             if(trie[par_link]->child.find(c) != trie[par_link]->child.end())
  74.             {
  75.                 trie[cur]->suffix_link = trie[par_link]->child[c];
  76.                 break;
  77.             }
  78.  
  79.             if(par_link == root)
  80.             {
  81.                 trie[cur]->suffix_link = root;
  82.                 break;
  83.             }
  84.  
  85.             par_link = trie[par_link]->suffix_link;
  86.         }
  87.  
  88.         // if cur's suffix link is a word, then cur's dict suffix link is cur's suffix link
  89.         // otherwise, cur's suffix link is cur's suffix link's dict suffix link
  90.         if(trie[trie[cur]->suffix_link]->leaf) trie[cur]->dict_suffix_link = trie[cur]->suffix_link;
  91.         else trie[cur]->dict_suffix_link = trie[trie[cur]->suffix_link]->dict_suffix_link;
  92.     }
  93.  
  94.     // BFS to call calc_suffix_link on each node
  95.     void prep()
  96.     {
  97.         queue<int> q;
  98.         q.push(root);
  99.         while(!q.empty())
  100.         {
  101.             int cur = q.front(); q.pop();
  102.             calc_suffix_link(cur);
  103.             for( auto p : trie[cur]->child )
  104.                 q.push(p.second);
  105.         }
  106.     }
  107.  
  108.     int process(string t)
  109.     {
  110.         int cur = root;
  111.         int result = 0;
  112.  
  113.         // for each character in t
  114.         for(int j=0;j<t.size();j++)
  115.         {
  116.  
  117.             // if t[j] is a child of the current node, move to that child
  118.             // otherwise move to its suffix link
  119.             // stop if we hit the root
  120.             while(true)
  121.             {
  122.                 if(trie[cur]->child.find(t[j]) != trie[cur]->child.end())
  123.                 {
  124.                     cur = trie[cur]->child[t[j]];
  125.                     break;
  126.                 }
  127.  
  128.                 if(cur == root) break;
  129.                
  130.                 cur = trie[cur] -> suffix_link;
  131.             }
  132.  
  133.             // if cur is a leaf, we have found a match
  134.             if(trie[cur]->leaf)
  135.             {
  136.                 string word = words[trie[cur]->word_id];
  137.                 int index_of_match = j - word.size() + 1;
  138.                 cout << "Found "<< word << " at "<<index_of_match<<'\n';
  139.                 result++;
  140.             }
  141.  
  142.             // print all matches that end at the current character
  143.             int check = cur;
  144.             while(true)
  145.             {
  146.                 check = trie[check]->dict_suffix_link;
  147.                 if(check==root) break;
  148.  
  149.                 string word = words[trie[check]->word_id];
  150.                 int index_of_match = j - word.size() + 1;
  151.                 cout << "Found "<< word << " at "<<index_of_match<<'\n';
  152.                 result++;
  153.             }
  154.  
  155.         }
  156.  
  157.         return result;
  158.     }
  159.  
  160. };
  161.  
  162. int main()
  163. {
  164.     aho a;
  165.     a.insert("a");
  166.     a.insert("ab");
  167.     a.insert("bab");
  168.     a.insert("bc");
  169.     a.insert("bca");
  170.     a.insert("c");
  171.     a.insert("caa");
  172.     a.prep();
  173.  
  174.     a.process("abccab");
  175.  
  176. }
Advertisement
Add Comment
Please, Sign In to add comment