zoukankan      html  css  js  c++  java
  • 4.【ac自动机】模式串匹配

    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] !='') {
                        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
    ", count/1000);
                    if (trie[k].strInfo[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叉树可解决此问题

  • 相关阅读:
    新手入门贴之基于 python 语言的接口自动化 demo 小实战
    记新人从 excel 文件中读取字典数据踩的一个坑
    接口自动化 之 unittest+ddt+openpyxl 综合
    接口自动化之unittest+ddt
    接口自动化之unittest初探
    python之类与对象(5)
    python之类与对象(4)
    python之类与对象(3)
    python之类与对象(2)
    传智播客JavaWeb day01 快捷键、XML
  • 原文地址:https://www.cnblogs.com/apo2019/p/11957488.html
Copyright © 2011-2022 走看看