Trie 图就是在 Trie 树上建立 fail 指针,类似于KMP算法中的next数组的作用。
这个数据结构的作用是判断一个字符串中是否包含一组字符串中的任意一个。
结构体定义是这样的:
typedef struct trie_node { trie_node *nodes[26]; trie_node *fail = NULL; bool word_end = false; trie_node() { for (int i = 0; i < 26; i++) { nodes[i] = NULL; } } } Trie, *PTrie;
与KMP类似,fail的定义如下:
记S[pnode]为从proot到pnode构成的字符串,所有满足S[i]是S[node]后缀串的节点i构成集合M,pnode->fail是集合M中使得S[pnode->fail]字符串长度最长的节点。
定义起来很拗口,但是如果理解KMP算法的话,fail和next的定义几乎一样。
求法也是相似的,用父节点的fail指针迭代求解。由于要利用父节点的信息,所以用层次遍历(bfs)的方法求解Trie树上每个节点的fail。
void trie_map(PTrie proot) { queue<PTrie> q; proot->fail = NULL; q.push(proot); while (!q.empty()) { PTrie pnode = q.front();q.pop(); PTrie pfail; for (int i = 0; i < 26; i++) { if (pnode->nodes[i] != NULL) { q.push(pnode->nodes[i]); pfail = pnode->fail; while (pfail != NULL) { if (pfail->nodes[i]) break; else pfail = pfail->fail; } pnode->nodes[i]->fail = pfail == NULL ? proot : pfail->nodes[i]; } } } }
hexie词匹配就是在树上不断匹配当前字符,遇到不匹配就转到fail节点继续匹配当前字符,一旦途中走到了一个单词结尾的节点就返回1,若匹配完整个字符串还没有返回,说明没有匹配到hexie词,返回0。
bool hexie(PTrie proot, char *str) { PTrie pcur = proot; int str_len = strlen(str); for (int i = 0; i < str_len; i++) { int pos = str[i] - ‘a‘; if (pcur->nodes[pos] != NULL) { pcur = pcur->nodes[pos]; } else { pcur = pcur->fail; if (pcur == NULL) { pcur = proot; continue; } i--; } if (pcur->word_end) return true; } return false; }
总而言之,Trie图跟KMP很像。可以说KMP是Trie图的特例、KMP是Trie树退化成链表后构成的Trie图。理解了KMP与Trie树,Trie图应该不在话下。
时间: 2024-12-07 00:33:22