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\n", 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\n", 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\n", count/1000); if (trie[k].strInfo[0] !=‘\0‘) { trie[k].flag++; } k = trie[k].fail; } u = trie[u].son[v]; } else { uint8_t vv = ((uint8_t)s[i / 2] << 4); uint8_t v = vv >> 4; k = trie[u].son[v]; while (k > 1) { count++; if (count % 10000000 == 0) printf("查询中...%lld\n", count/1000); if (trie[k].strInfo[0] != ‘\0‘) { trie[k].flag++; } k = trie[k].fail; //继续跳Fail } u = trie[u].son[v];//到下一个儿子 } } return count; }
4.堆排
void HeapAdjust(txt* data, int s, int m)//s=3,m=7 s=2 s是广义上的根 (下一根 ) { txt temp; int i; temp = data[s];//a[3] for (i = 2 * s + 1; i <= m; i = i * 2 + 1)//i=7;i<=7; i=5 i为根s的子树结点 { //printf("k%d",a[i+1]); if (i<m && data[i].appearNum>data[i + 1].appearNum) //i为小子树 i++; if (!(temp.appearNum > data[i].appearNum)) //初始根根和小子树比较,根小于等于小子树,退出 ; 这个temp根是初始根,并非下一根 子树可能是儿子或孙子... break; data[s] = data[i];//初始根大于 小子树值 (这里并不一定是父子比较,第二次可能是爷孙比较)s广义根变小子树值 s = i;//继续判断下一根 直到叶子结点 } data[s] = temp;//叶子结点值变初始根值 } void HeapSort(txt* data, int size) { int i, j; txt temp; for (i = (size - 1) / 2; i >= 0; i--)//i=(8-1)/2=3 HeapAdjust(data, i, size - 1);//a,3,7 a,2,7 a,1,7 a,0,7 循环调整 建立小根堆 for (i = size - 1; i > 0; i--) { temp = data[0]; data[0] = data[i]; data[i] = temp; HeapAdjust(data, 0, i - 1); } }
5.问题:中文2字节编码后,拆成4个16进制,会出现杂糅问题。例如你好(C4E3BAC3)可能识别出愫(E3BA),模式串越短错误率越高,尤其是单字母的英文模式串。但词组错误率几乎为零。256叉树可解决此问题
原文地址:https://www.cnblogs.com/apo2019/p/11957488.html
时间: 2024-10-05 05:01:24