ANSI编码的中英文16叉模式串匹配自动机
1.构造模式串树
void insert(char* s, in* trie) { long u = 1, len = strlen(s);//每来一个模式串 for (long i = 0; i < len * 2; i++) { if (i % 2 == 0) { uint8_t vv = (uint8_t)s[i / 2]; uint8_t v = vv >> 4; if (!trie[u].son[v]) trie[u].son[v] = ++cnt; u = trie[u].son[v]; } else { uint8_t vv = ((uint8_t)s[i / 2] << 4); uint8_t v = vv >> 4;//s[i]后四位 if (!trie[u].son[v]) trie[u].son[v] = ++cnt; u = trie[u].son[v]; } } trie[u].patternNum++; if (strcmp(trie[u].strInfo, s)) { strcat(trie[u].strInfo, s); if (u % 100000 == 0)printf("建树中... %d ", u); //不可使用指针! } }
2.得到fail指针
void getFail(in* trie) { long u, y; for (long i = 0; i < 16; i++) { trie[0].son[i] = 1; //初始化0的所有儿子都是1 所有的树型有限自动机都有一个共同的特点,即对任何输入字符a, 都有g(0, a) != 0。 } queue_push(&q, 1); trie[1].fail = 0; //将根压入队列 while (!queue_empty(&q)) { queue_front(&q, &u); queue_pop(&q, &y); for (long i = 0; i < 16; i++) { //遍历所有儿子 long v = trie[u].son[i]; //处理u的i儿子的fail,这样就可以不用记父亲了 long Fail = trie[u].fail; //就是fafail,trie[Fail].son[i]就是和v值相同的点 if (!v) { trie[u].son[i] = trie[Fail].son[i]; continue; } //不存在该节点,第二种情况 trie[v].fail = trie[Fail].son[i]; //第三种情况,直接指就可以了 //printf("%d %d ", v, trie[Fail].son[i]); queue_push(&q, v); //存在实节点才压入队列 } } }
3.主串查询(不回溯)
long query(char* s, long len, in* trie) { long u = 1; for (long i = 0; i < len * 2; i++) { long k = 0; if (i % 2 == 0) { uint8_t vv = (uint8_t)s[i / 2]; uint8_t v = vv >> 4; k = trie[u].son[v]; while (k > 1) { count++; if (count % 10000000 == 0) printf("查询中...%lld ", count/1000); if (trie[k].strInfo[0] !='