summaryrefslogtreecommitdiff
path: root/string/ahoCorasick.cpp
blob: d221fcbd1a095b722f19b3e5fee22a7542a05b4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Laufzeit: O(n + m + z), n = #Text, m = Summe #Pattern, z = #Matches
// Findet mehrere Patterns gleichzeitig in einem String.
// 1) Wurzel erstellen: aho.push_back(vertex());
// 2) Mit addString(0, pattern, idx); Patterns hinzufügen.
// 3) finishAutomaton(0) aufrufen.
// 4) Mit state = go(state, c) in nächsten Zustand wechseln.
//    DANACH: Wenn patterns-Vektor nicht leer ist: Hier enden alle
//    enthaltenen Patterns.
// ACHTUNG: Die Zahlenwerte der auftretenden Buchstaben müssen
// zusammenhängend sein und bei 0 beginnen!
struct vertex {
  int next[ALPHABET_SIZE], failure;
  int character; 
  vector<int> patterns; // Indizes der Patterns, die hier enden.
  vertex() { for (int i = 0; i < ALPHABET_SIZE; i++) next[i] = -1; }
};
vector<vertex> aho;

void addString(int v, vector<int> &pattern, int patternIdx) {
  for (int i = 0; i < (int)pattern.size(); i++) {
    if (aho[v].next[pattern[i]] == -1) {
      aho[v].next[pattern[i]] = aho.size();
      aho.push_back(vertex());
      aho.back().character = pattern[i];
    }
    v = aho[v].next[pattern[i]];
  }
  aho[v].patterns.push_back(patternIdx);
}

void finishAutomaton(int v) {
  for (int i = 0; i < ALPHABET_SIZE; i++)
    if (aho[v].next[i] == -1) aho[v].next[i] = v;

  queue<int> q;
  for (int i = 0; i < ALPHABET_SIZE; i++) {
    if (aho[v].next[i] != v) {
      aho[aho[v].next[i]].failure = v;
      q.push(aho[v].next[i]);
  }}
  while (!q.empty()) {
    int r = q.front(); q.pop();
    for (int i = 0; i < ALPHABET_SIZE; i++) {
      if (aho[r].next[i] != -1) {
        q.push(aho[r].next[i]);
        int f = aho[r].failure;
        while (aho[f].next[i] == -1) f = aho[f].failure;
        aho[aho[r].next[i]].failure = aho[f].next[i];
        for (int j = 0; j < (int)aho[aho[f].next[i]].patterns.size(); j++) {
          aho[aho[r].next[i]].patterns.push_back(
              aho[aho[f].next[i]].patterns[j]);
}}}}}

int go(int v, int c) {
  if (aho[v].next[c] != -1) return aho[v].next[c];
  else return go(aho[v].failure, c);
}