Kyopro Library
 
読み取り中…
検索中…
一致する文字列を見つけられません
aho.hpp
[詳解]
1///@brief Trie, Aho-Corasick
2//https://ei1333.github.io/library/string/aho-corasick.hpp に適宜コメントを付けただけです
3
4///@brief TrieNode
5///@tparam char_size アルファベットのサイズ
6template <int char_size>
7struct TrieNode {
8 int nxt[char_size];///<子どものノードのインデクス, ないなら-1
9 int exist;///<このノードをprefixとして持つ文字列の個数
10 vector<int> accept;///<このノードが終点である文字列の個数
11
12 TrieNode() : exist(0) { memset(nxt, -1, sizeof(nxt)); }
13};
14
15///@brief Trie
16///@tparam char_size アルファベットのサイズ
17///@tparam margin 0にあたる文字
18template <int char_size, int margin>
19struct Trie {
20 using Node = TrieNode<char_size>;
21
23 int root;
24
25 Trie() : root(0) { nodes.push_back(Node()); }
26
27 void update_direct(int node, int id) { nodes[node].accept.push_back(id); }
28
29 void update_child(int node, int child, int id) { ++nodes[node].exist; }
30
31 void add(const string& str, int str_index, int node_index, int id) {
32 if (str_index == str.size()) {
33 update_direct(node_index, id);
34 } else {
35 const int c = str[str_index] - margin;
36 if (nodes[node_index].nxt[c] == -1) {
37 nodes[node_index].nxt[c] = (int)nodes.size();
38 nodes.push_back(Node());
39 }
40 add(str, str_index + 1, nodes[node_index].nxt[c], id);
41 update_child(node_index, nodes[node_index].nxt[c], id);
42 }
43 }
44
45 void add(const string& str, int id) { add(str, 0, 0, id); }
46
47 ///@brief 文字列 str を追加する
48 void add(const string& str) { add(str, nodes[0].exist); }
49
50 void query(const string& str, const function<void(int)>& f, int str_index,
51 int node_index) {
52 for (auto& idx : nodes[node_index].accept) f(idx);
53 if (str_index == str.size()) {
54 return;
55 } else {
56 const int c = str[str_index] - margin;
57 if (nodes[node_index].nxt[c] == -1) return;
58 query(str, f, str_index + 1, nodes[node_index].nxt[c]);
59 }
60 }
61
62 ///@brief strをprefixとして持つ全ての文字列に対し、見つかった文字列のインデックスそれぞれに対してfを実行する
63 void query(const string& str, const function<void(int)>& f) {
64 query(str, f, 0, 0);
65 }
66
67 ///@brief 文字列の総数
68 int count() const { return (nodes[0].exist); }
69
70 ///@brief ノードの総数
71 int size() const { return ((int)nodes.size()); }
72};
73
74///@brief AhoCorasick
75template <int char_size, int margin>
76struct AhoCorasick : Trie<char_size + 1, margin> {
77 using Trie<char_size + 1, margin>::Trie;
78
79 const int FAIL = char_size;
81
82 ///@brief 前計算 オートマトンを構築する
83 void build(bool heavy = true) {
84 correct.resize(this->size());
85 for (int i = 0; i < this->size(); i++) {
86 correct[i] = (int)this->nodes[i].accept.size();
87 }
88 queue<int> que;
89 for (int i = 0; i <= char_size; i++) {
90 if (~this->nodes[0].nxt[i]) {
91 this->nodes[this->nodes[0].nxt[i]].nxt[FAIL] = 0;
92 que.emplace(this->nodes[0].nxt[i]);
93 } else {
94 this->nodes[0].nxt[i] = 0;
95 }
96 }
97 while (!que.empty()) {
98 auto& now = this->nodes[que.front()];
99 int fail = now.nxt[FAIL];
100 correct[que.front()] += correct[fail];
101 que.pop();
102 for (int i = 0; i < char_size; i++) {
103 if (~now.nxt[i]) {
104 this->nodes[now.nxt[i]].nxt[FAIL] = this->nodes[fail].nxt[i];
105 if (heavy) {
106 auto& u = this->nodes[now.nxt[i]].accept;
107 auto& v = this->nodes[this->nodes[fail].nxt[i]].accept;
108 vector<int> accept;
109 set_union(begin(u), end(u), begin(v), end(v),
110 back_inserter(accept));
111 u = accept;
112 }
113 que.emplace(now.nxt[i]);
114 } else {
115 now.nxt[i] = this->nodes[fail].nxt[i];
116 }
117 }
118 }
119 }
120
121 ///@brief str の中に出現する全パターンの出現回数を返す
122 unordered_map<int, int> match(const string& str, int now = 0) {
123 unordered_map<int, int> result, visit_cnt;
124 for (auto& c : str) {
125 now = this->nodes[now].nxt[c - margin];
126 visit_cnt[now]++;
127 }
128 for (auto& [now, cnt] : visit_cnt) {
129 for (auto& v : this->nodes[now].accept) result[v] += cnt;
130 }
131 return result;
132 }
133
134 ///@brief 現在のノード now から文字 c で遷移したときの(見つかったパターンの総数, 次のノード)を返す
135 pair<int64_t, int> move(const char& c, int now = 0) {
136 now = this->nodes[now].nxt[c - margin];
137 return {correct[now], now};
138 }
139
140 ///@brief str に対して move を適用する。(見つかったパターンの総数, 最終ノードを返す)
141 pair<int64_t, int> move(const string& str, int now = 0) {
142 int64_t sum = 0;
143 for (auto& c : str) {
144 auto nxt = move(c, now);
145 sum += nxt.first;
146 now = nxt.second;
147 }
148 return {sum, now};
149 }
150};
AhoCorasick
Definition aho.hpp:76
vector< int > correct
Definition aho.hpp:80
void build(bool heavy=true)
前計算 オートマトンを構築する
Definition aho.hpp:83
const int FAIL
Definition aho.hpp:79
pair< int64_t, int > move(const char &c, int now=0)
現在のノード now から文字 c で遷移したときの(見つかったパターンの総数, 次のノード)を返す
Definition aho.hpp:135
unordered_map< int, int > match(const string &str, int now=0)
str の中に出現する全パターンの出現回数を返す
Definition aho.hpp:122
pair< int64_t, int > move(const string &str, int now=0)
str に対して move を適用する。(見つかったパターンの総数, 最終ノードを返す)
Definition aho.hpp:141
Trie
Definition aho.hpp:19
void update_direct(int node, int id)
Definition aho.hpp:27
int size() const
ノードの総数
Definition aho.hpp:71
vector< Node > nodes
Definition aho.hpp:22
void query(const string &str, const function< void(int)> &f)
strをprefixとして持つ全ての文字列に対し、見つかった文字列のインデックスそれぞれに対してfを実行する
Definition aho.hpp:63
void add(const string &str, int str_index, int node_index, int id)
Definition aho.hpp:31
Trie()
Definition aho.hpp:25
void add(const string &str)
文字列 str を追加する
Definition aho.hpp:48
int count() const
文字列の総数
Definition aho.hpp:68
void add(const string &str, int id)
Definition aho.hpp:45
void query(const string &str, const function< void(int)> &f, int str_index, int node_index)
Definition aho.hpp:50
void update_child(int node, int child, int id)
Definition aho.hpp:29
int root
Definition aho.hpp:23
Trie, Aho-Corasick
Definition aho.hpp:7
int exist
このノードをprefixとして持つ文字列の個数
Definition aho.hpp:9
TrieNode()
Definition aho.hpp:12
vector< int > accept
このノードが終点である文字列の個数
Definition aho.hpp:10
int nxt[char_size]
子どものノードのインデクス, ないなら-1
Definition aho.hpp:8